1 /*
2 * Copyright © Microsoft Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24 #include "d3d12_video_buffer.h"
25 #include "d3d12_video_enc.h"
26 #include "d3d12_resource.h"
27 #include "d3d12_video_dec.h"
28 #include "d3d12_residency.h"
29 #include "d3d12_context.h"
30
31 #include "util/format/u_format.h"
32 #include "util/u_inlines.h"
33 #include "util/u_memory.h"
34 #include "util/u_video.h"
35 #include "vl/vl_video_buffer.h"
36 #include "util/u_sampler.h"
37 #include "frontend/winsys_handle.h"
38 #include "d3d12_format.h"
39 #include "d3d12_screen.h"
40
41 static struct pipe_video_buffer *
d3d12_video_buffer_create_impl(struct pipe_context * pipe,const struct pipe_video_buffer * tmpl,struct pipe_resource * resource_creation_info,d3d12_video_buffer_creation_mode resource_creation_mode,struct winsys_handle * handle,unsigned usage)42 d3d12_video_buffer_create_impl(struct pipe_context *pipe,
43 const struct pipe_video_buffer *tmpl,
44 struct pipe_resource* resource_creation_info,
45 d3d12_video_buffer_creation_mode resource_creation_mode,
46 struct winsys_handle *handle,
47 unsigned usage)
48 {
49 assert(pipe);
50 assert(tmpl);
51
52 ///
53 /// Initialize d3d12_video_buffer
54 ///
55
56 // Not using new doesn't call ctor and the initializations in the class declaration are lost
57 struct d3d12_video_buffer *pD3D12VideoBuffer = new d3d12_video_buffer;
58
59 // Fill base template
60 pD3D12VideoBuffer->base = *tmpl;
61 pD3D12VideoBuffer->base.buffer_format = tmpl->buffer_format;
62 pD3D12VideoBuffer->base.context = pipe;
63 pD3D12VideoBuffer->base.width = tmpl->width;
64 pD3D12VideoBuffer->base.height = tmpl->height;
65 pD3D12VideoBuffer->base.interlaced = tmpl->interlaced;
66 pD3D12VideoBuffer->base.contiguous_planes = true;
67 pD3D12VideoBuffer->base.associated_data = nullptr;
68 pD3D12VideoBuffer->idx_texarray_slots = 0;
69 pD3D12VideoBuffer->m_spVideoTexArrayDPBPoolInUse.reset();
70
71 // Used to signal the rest of the d3d12 driver this is a video (dpb or not) texture
72 pD3D12VideoBuffer->base.bind |= PIPE_BIND_CUSTOM;
73 #ifdef HAVE_GALLIUM_D3D12_GRAPHICS
74 struct d3d12_screen *dscreen = (struct d3d12_screen*) pipe->screen;
75 if ((dscreen->max_feature_level >= D3D_FEATURE_LEVEL_11_0) &&
76 ((pD3D12VideoBuffer->base.bind & PIPE_BIND_VIDEO_DECODE_DPB) == 0) &&
77 ((pD3D12VideoBuffer->base.bind & PIPE_BIND_VIDEO_ENCODE_DPB) == 0))
78 pD3D12VideoBuffer->base.bind |= (PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW);
79 #endif // HAVE_GALLIUM_D3D12_GRAPHICS
80
81 // Fill vtable
82 pD3D12VideoBuffer->base.destroy = d3d12_video_buffer_destroy;
83 pD3D12VideoBuffer->base.get_resources = d3d12_video_buffer_resources;
84 pD3D12VideoBuffer->base.get_sampler_view_planes = d3d12_video_buffer_get_sampler_view_planes;
85 pD3D12VideoBuffer->base.get_sampler_view_components = d3d12_video_buffer_get_sampler_view_components;
86 pD3D12VideoBuffer->base.get_surfaces = d3d12_video_buffer_get_surfaces;
87 pD3D12VideoBuffer->base.destroy_associated_data = d3d12_video_buffer_destroy_associated_data;
88
89 ///
90 /// Create, open or place underlying pipe_resource allocation
91 ///
92
93 // This calls d3d12_create_resource as the function ptr is set in d3d12_screen.resource_create
94 if (resource_creation_mode == d3d12_video_buffer_creation_mode::open_shared_resource)
95 {
96 assert(handle);
97 resource_creation_info->target = PIPE_TEXTURE_2D;
98 resource_creation_info->bind = pD3D12VideoBuffer->base.bind;
99 resource_creation_info->format = pD3D12VideoBuffer->base.buffer_format;
100 resource_creation_info->flags = 0;
101 resource_creation_info->depth0 = 1;
102 if (resource_creation_info->array_size == 0) // If caller did not pass it, set as 1 default
103 resource_creation_info->array_size = 1;
104
105 // YUV 4:2:0 formats in D3D12 always require multiple of 2 dimensions
106 // We must respect the input dimensions of the imported resource handle (e.g no extra aligning)
107 resource_creation_info->width0 = align(pD3D12VideoBuffer->base.width, 2);
108 resource_creation_info->height0 = align(pD3D12VideoBuffer->base.height, 2);
109
110 // WINSYS_HANDLE_TYPE_D3D12_RES implies taking ownership of the reference
111 if(handle->type == WINSYS_HANDLE_TYPE_D3D12_RES)
112 ((IUnknown *)handle->com_obj)->AddRef();
113 pD3D12VideoBuffer->texture = (struct d3d12_resource *) pipe->screen->resource_from_handle(pipe->screen, resource_creation_info, handle, usage);
114 }
115 else if(resource_creation_mode == d3d12_video_buffer_creation_mode::create_resource)
116 {
117 resource_creation_info->target = PIPE_TEXTURE_2D;
118 resource_creation_info->bind = pD3D12VideoBuffer->base.bind;
119 resource_creation_info->format = pD3D12VideoBuffer->base.buffer_format;
120 resource_creation_info->flags = 0;
121 resource_creation_info->depth0 = 1;
122 if (resource_creation_info->array_size == 0) // If caller did not pass it, set as 1 default
123 resource_creation_info->array_size = 1;
124
125 // When creating (e.g not importing) resources we allocate
126 // with a higher alignment to maximize HW compatibility
127 resource_creation_info->width0 = align(pD3D12VideoBuffer->base.width, 2);
128 resource_creation_info->height0 = align(pD3D12VideoBuffer->base.height, 16);
129
130 pD3D12VideoBuffer->texture = (struct d3d12_resource *) pipe->screen->resource_create(pipe->screen, resource_creation_info);
131 }
132 else if(resource_creation_mode == d3d12_video_buffer_creation_mode::place_on_resource)
133 {
134 pD3D12VideoBuffer->texture = (struct d3d12_resource*) resource_creation_info; // Set directly the resource as underlying texture
135 }
136
137 if (pD3D12VideoBuffer->texture == nullptr) {
138 debug_printf("[d3d12_video_buffer] d3d12_video_buffer_create_impl - failed to set a valid pD3D12VideoBuffer->texture.");
139 goto failed;
140 }
141
142 d3d12_promote_to_permanent_residency((struct d3d12_screen*) pipe->screen, pD3D12VideoBuffer->texture);
143
144 pD3D12VideoBuffer->num_planes = util_format_get_num_planes(pD3D12VideoBuffer->texture->overall_format);
145 return &pD3D12VideoBuffer->base;
146
147 failed:
148 d3d12_video_buffer_destroy((struct pipe_video_buffer *) pD3D12VideoBuffer);
149
150 return nullptr;
151 }
152
153 /**
154 * creates a video buffer from a handle
155 */
156 struct pipe_video_buffer *
d3d12_video_buffer_from_handle(struct pipe_context * pipe,const struct pipe_video_buffer * tmpl,struct winsys_handle * handle,unsigned usage)157 d3d12_video_buffer_from_handle(struct pipe_context *pipe,
158 const struct pipe_video_buffer *tmpl,
159 struct winsys_handle *handle,
160 unsigned usage)
161 {
162 struct pipe_video_buffer updated_template = {};
163 if ((handle->format == PIPE_FORMAT_NONE) || (tmpl == nullptr) || (tmpl->buffer_format == PIPE_FORMAT_NONE) ||
164 (tmpl->width == 0) || (tmpl->height == 0)) {
165 ID3D12Resource *d3d12_res = nullptr;
166 if (handle->type == WINSYS_HANDLE_TYPE_D3D12_RES) {
167 d3d12_res = (ID3D12Resource *) handle->com_obj;
168 } else if (handle->type == WINSYS_HANDLE_TYPE_FD) {
169 #ifdef _WIN32
170 HANDLE d3d_handle = handle->handle;
171 #else
172 HANDLE d3d_handle = (HANDLE) (intptr_t) handle->handle;
173 #endif
174 if (FAILED(d3d12_screen(pipe->screen)->dev->OpenSharedHandle(d3d_handle, IID_PPV_ARGS(&d3d12_res)))) {
175 return NULL;
176 }
177 }
178 D3D12_RESOURCE_DESC res_desc = GetDesc(d3d12_res);
179 updated_template.width = res_desc.Width;
180 updated_template.height = res_desc.Height;
181 updated_template.buffer_format = d3d12_get_pipe_format(res_desc.Format);
182 handle->format = updated_template.buffer_format;
183
184 // if passed an external com_ptr (e.g WINSYS_HANDLE_TYPE_D3D12_RES) do not release it
185 if (handle->type == WINSYS_HANDLE_TYPE_FD)
186 d3d12_res->Release();
187 } else {
188 updated_template = *tmpl;
189 }
190
191 pipe_resource resource_creation_info = {};
192 return d3d12_video_buffer_create_impl(pipe, &updated_template, &resource_creation_info, d3d12_video_buffer_creation_mode::open_shared_resource, handle, usage);
193 }
194
195 /**
196 * creates a video buffer
197 */
198 struct pipe_video_buffer *
d3d12_video_buffer_create(struct pipe_context * pipe,const struct pipe_video_buffer * tmpl)199 d3d12_video_buffer_create(struct pipe_context *pipe, const struct pipe_video_buffer *tmpl)
200 {
201 pipe_resource resource_creation_info = {};
202 return d3d12_video_buffer_create_impl(pipe, tmpl, &resource_creation_info, d3d12_video_buffer_creation_mode::create_resource, NULL, 0);
203 }
204
205 /**
206 * destroy this video buffer
207 */
208 void
d3d12_video_buffer_destroy(struct pipe_video_buffer * buffer)209 d3d12_video_buffer_destroy(struct pipe_video_buffer *buffer)
210 {
211 struct d3d12_video_buffer *pD3D12VideoBuffer = (struct d3d12_video_buffer *) buffer;
212
213 // For texture arrays, only delete the underlying resource allocation when
214 // there are no more in use slots into it
215 bool bKeepUnderlyingAlloc = false;
216 if (pD3D12VideoBuffer->texture->base.b.array_size > 1)
217 {
218 // Mark slot used by the video buffer being destroyed as unused
219 (*pD3D12VideoBuffer->m_spVideoTexArrayDPBPoolInUse) &= ~(1 << pD3D12VideoBuffer->idx_texarray_slots); // mark bit idx_texarray_slots as zero
220 // Keep underlying pD3D12VideoBuffer->texture alloc if any other slots are in use.
221 bKeepUnderlyingAlloc = (*pD3D12VideoBuffer->m_spVideoTexArrayDPBPoolInUse != 0); // check for any non-zero bit
222 }
223
224 // Destroy pD3D12VideoBuffer->texture underlying aloc
225 if (pD3D12VideoBuffer->texture && !bKeepUnderlyingAlloc) {
226 pipe_resource *pBaseResource = &pD3D12VideoBuffer->texture->base.b;
227 pipe_resource_reference(&pBaseResource, NULL);
228 }
229
230 // Destroy associated data (if any)
231 if (pD3D12VideoBuffer->base.associated_data != nullptr) {
232 d3d12_video_buffer_destroy_associated_data(pD3D12VideoBuffer->base.associated_data);
233 // Set to nullptr after cleanup, no dangling pointers
234 pD3D12VideoBuffer->base.associated_data = nullptr;
235 }
236
237 for (uint i = 0; i < pD3D12VideoBuffer->surfaces.size(); ++i) {
238 if (pD3D12VideoBuffer->surfaces[i] != NULL) {
239 pipe_surface_reference(&pD3D12VideoBuffer->surfaces[i], NULL);
240 }
241 }
242
243 for (uint i = 0; i < pD3D12VideoBuffer->sampler_view_planes.size(); ++i) {
244 if (pD3D12VideoBuffer->sampler_view_planes[i] != NULL) {
245 pipe_sampler_view_reference(&pD3D12VideoBuffer->sampler_view_planes[i], NULL);
246 }
247 }
248
249 for (uint i = 0; i < pD3D12VideoBuffer->sampler_view_components.size(); ++i) {
250 if (pD3D12VideoBuffer->sampler_view_components[i] != NULL) {
251 pipe_sampler_view_reference(&pD3D12VideoBuffer->sampler_view_components[i], NULL);
252 }
253 }
254
255 delete pD3D12VideoBuffer;
256 }
257
258 /*
259 * destroy the associated data
260 */
261 void
d3d12_video_buffer_destroy_associated_data(void * associated_data)262 d3d12_video_buffer_destroy_associated_data(void *associated_data)
263 { }
264
265 /**
266 * get an individual surfaces for each plane
267 */
268 struct pipe_surface **
d3d12_video_buffer_get_surfaces(struct pipe_video_buffer * buffer)269 d3d12_video_buffer_get_surfaces(struct pipe_video_buffer *buffer)
270 {
271 assert(buffer);
272 struct d3d12_video_buffer *pD3D12VideoBuffer = (struct d3d12_video_buffer *) buffer;
273 struct pipe_context * pipe = pD3D12VideoBuffer->base.context;
274 struct pipe_surface surface_template = {};
275
276 // DPB buffers don't support views
277 if ((pD3D12VideoBuffer->base.bind & PIPE_BIND_VIDEO_DECODE_DPB) ||
278 (pD3D12VideoBuffer->base.bind & PIPE_BIND_VIDEO_ENCODE_DPB))
279 return nullptr;
280
281 if (!pipe->create_surface)
282 return nullptr;
283
284 // Some video frameworks iterate over [0..VL_MAX_SURFACES) and ignore the nullptr entries
285 // So we have to null initialize the other surfaces not used from [num_planes..VL_MAX_SURFACES)
286 // Like in src/gallium/frontends/va/surface.c
287 pD3D12VideoBuffer->surfaces.resize(VL_MAX_SURFACES, nullptr);
288
289 // pCurPlaneResource refers to the planar resource, not the overall resource.
290 // in d3d12_resource this is handled by having a linked list of planes with
291 // d3dRes->base.next ptr to next plane resource
292 // starting with the plane 0 being the overall resource
293 struct pipe_resource *pCurPlaneResource = &pD3D12VideoBuffer->texture->base.b;
294
295 for (uint PlaneSlice = 0; PlaneSlice < pD3D12VideoBuffer->num_planes; ++PlaneSlice) {
296 if (!pD3D12VideoBuffer->surfaces[PlaneSlice]) {
297 memset(&surface_template, 0, sizeof(surface_template));
298 surface_template.format =
299 util_format_get_plane_format(pD3D12VideoBuffer->texture->overall_format, PlaneSlice);
300
301 pD3D12VideoBuffer->surfaces[PlaneSlice] =
302 pipe->create_surface(pipe, pCurPlaneResource, &surface_template);
303
304 if (!pD3D12VideoBuffer->surfaces[PlaneSlice]) {
305 goto error;
306 }
307 }
308 pCurPlaneResource = pCurPlaneResource->next;
309 }
310
311 return pD3D12VideoBuffer->surfaces.data();
312
313 error:
314 for (uint PlaneSlice = 0; PlaneSlice < pD3D12VideoBuffer->num_planes; ++PlaneSlice) {
315 pipe_surface_reference(&pD3D12VideoBuffer->surfaces[PlaneSlice], NULL);
316 }
317
318 return nullptr;
319 }
320
321 /**
322 * get an individual resource for each plane,
323 * only returns existing resources by reference
324 */
325 void
d3d12_video_buffer_resources(struct pipe_video_buffer * buffer,struct pipe_resource ** resources)326 d3d12_video_buffer_resources(struct pipe_video_buffer *buffer,
327 struct pipe_resource **resources)
328 {
329 struct d3d12_video_buffer *pD3D12VideoBuffer = (struct d3d12_video_buffer *) buffer;
330 assert(pD3D12VideoBuffer);
331
332 // pCurPlaneResource refers to the planar resource, not the overall resource.
333 // in d3d12_resource this is handled by having a linked list of planes with
334 // d3dRes->base.next ptr to next plane resource
335 // starting with the plane 0 being the overall resource
336 struct pipe_resource *pCurPlaneResource = &pD3D12VideoBuffer->texture->base.b;
337
338 for (uint i = 0; i < pD3D12VideoBuffer->num_planes; ++i) {
339 assert(pCurPlaneResource); // the d3d12_resource has a linked list with the exact name of number of elements
340 // as planes
341
342 resources[i] = pCurPlaneResource;
343 pCurPlaneResource = pCurPlaneResource->next;
344 }
345 }
346
347 /**
348 * get an individual sampler view for each plane
349 */
350 struct pipe_sampler_view **
d3d12_video_buffer_get_sampler_view_planes(struct pipe_video_buffer * buffer)351 d3d12_video_buffer_get_sampler_view_planes(struct pipe_video_buffer *buffer)
352 {
353 assert(buffer);
354 struct d3d12_video_buffer *pD3D12VideoBuffer = (struct d3d12_video_buffer *) buffer;
355 struct pipe_context * pipe = pD3D12VideoBuffer->base.context;
356 struct pipe_sampler_view samplerViewTemplate;
357
358 // DPB buffers don't support views
359 if ((pD3D12VideoBuffer->base.bind & PIPE_BIND_VIDEO_DECODE_DPB) ||
360 (pD3D12VideoBuffer->base.bind & PIPE_BIND_VIDEO_ENCODE_DPB))
361 return nullptr;
362
363 // Some video frameworks iterate over [0..VL_MAX_SURFACES) and ignore the nullptr entries
364 // So we have to null initialize the other surfaces not used from [num_planes..VL_MAX_SURFACES)
365 // Like in src/gallium/frontends/vdpau/surface.c
366 pD3D12VideoBuffer->sampler_view_planes.resize(VL_MAX_SURFACES, nullptr);
367
368 // pCurPlaneResource refers to the planar resource, not the overall resource.
369 // in d3d12_resource this is handled by having a linked list of planes with
370 // d3dRes->base.next ptr to next plane resource
371 // starting with the plane 0 being the overall resource
372 struct pipe_resource *pCurPlaneResource = &pD3D12VideoBuffer->texture->base.b;
373
374 for (uint i = 0; i < pD3D12VideoBuffer->num_planes; ++i) {
375 if (!pD3D12VideoBuffer->sampler_view_planes[i]) {
376 assert(pCurPlaneResource); // the d3d12_resource has a linked list with the exact name of number of elements
377 // as planes
378
379 memset(&samplerViewTemplate, 0, sizeof(samplerViewTemplate));
380 u_sampler_view_default_template(&samplerViewTemplate, pCurPlaneResource, pCurPlaneResource->format);
381
382 pD3D12VideoBuffer->sampler_view_planes[i] =
383 pipe->create_sampler_view(pipe, pCurPlaneResource, &samplerViewTemplate);
384
385 if (!pD3D12VideoBuffer->sampler_view_planes[i]) {
386 goto error;
387 }
388 }
389
390 pCurPlaneResource = pCurPlaneResource->next;
391 }
392
393 return pD3D12VideoBuffer->sampler_view_planes.data();
394
395 error:
396 for (uint i = 0; i < pD3D12VideoBuffer->num_planes; ++i) {
397 pipe_sampler_view_reference(&pD3D12VideoBuffer->sampler_view_planes[i], NULL);
398 }
399
400 return nullptr;
401 }
402
403 /**
404 * get an individual sampler view for each component
405 */
406 struct pipe_sampler_view **
d3d12_video_buffer_get_sampler_view_components(struct pipe_video_buffer * buffer)407 d3d12_video_buffer_get_sampler_view_components(struct pipe_video_buffer *buffer)
408 {
409 assert(buffer);
410 struct d3d12_video_buffer *pD3D12VideoBuffer = (struct d3d12_video_buffer *) buffer;
411 struct pipe_context * pipe = pD3D12VideoBuffer->base.context;
412 struct pipe_sampler_view samplerViewTemplate;
413
414 // DPB buffers don't support views
415 if ((pD3D12VideoBuffer->base.bind & PIPE_BIND_VIDEO_DECODE_DPB) ||
416 (pD3D12VideoBuffer->base.bind & PIPE_BIND_VIDEO_ENCODE_DPB))
417 return nullptr;
418
419 // pCurPlaneResource refers to the planar resource, not the overall resource.
420 // in d3d12_resource this is handled by having a linked list of planes with
421 // d3dRes->base.next ptr to next plane resource
422 // starting with the plane 0 being the overall resource
423 struct pipe_resource *pCurPlaneResource = &pD3D12VideoBuffer->texture->base.b;
424
425 const uint32_t MAX_NUM_COMPONENTS = 4; // ie. RGBA formats
426 // At the end of the loop, "component" will have the total number of items valid in sampler_view_components
427 // since component can end up being <= MAX_NUM_COMPONENTS, we assume MAX_NUM_COMPONENTS first and then resize/adjust to
428 // fit the container size pD3D12VideoBuffer->sampler_view_components to the actual components number
429 pD3D12VideoBuffer->sampler_view_components.resize(MAX_NUM_COMPONENTS, nullptr);
430 uint component = 0;
431
432 for (uint i = 0; i < pD3D12VideoBuffer->num_planes; ++i) {
433 // For example num_components would be 1 for the Y plane (R8 in NV12), 2 for the UV plane (R8G8 in NV12)
434 unsigned num_components = util_format_get_nr_components(pCurPlaneResource->format);
435
436 for (uint j = 0; j < num_components; ++j, ++component) {
437
438 if (!pD3D12VideoBuffer->sampler_view_components[component]) {
439 memset(&samplerViewTemplate, 0, sizeof(samplerViewTemplate));
440 u_sampler_view_default_template(&samplerViewTemplate, pCurPlaneResource, pCurPlaneResource->format);
441 samplerViewTemplate.swizzle_r = samplerViewTemplate.swizzle_g = samplerViewTemplate.swizzle_b =
442 PIPE_SWIZZLE_X + j;
443 samplerViewTemplate.swizzle_a = PIPE_SWIZZLE_1;
444
445 pD3D12VideoBuffer->sampler_view_components[component] =
446 pipe->create_sampler_view(pipe, pCurPlaneResource, &samplerViewTemplate);
447 if (!pD3D12VideoBuffer->sampler_view_components[component]) {
448 goto error;
449 }
450 }
451 }
452
453 pCurPlaneResource = pCurPlaneResource->next;
454 }
455
456 // Adjust size to fit component <= VL_NUM_COMPONENTS
457 pD3D12VideoBuffer->sampler_view_components.resize(component);
458
459 return pD3D12VideoBuffer->sampler_view_components.data();
460
461 error:
462 for (uint i = 0; i < pD3D12VideoBuffer->num_planes; ++i) {
463 pipe_sampler_view_reference(&pD3D12VideoBuffer->sampler_view_components[i], NULL);
464 }
465
466 return nullptr;
467 }
468
469 struct pipe_video_buffer*
d3d12_video_create_dpb_buffer(struct pipe_video_codec * codec,struct pipe_picture_desc * picture,const struct pipe_video_buffer * templat)470 d3d12_video_create_dpb_buffer(struct pipe_video_codec *codec,
471 struct pipe_picture_desc *picture,
472 const struct pipe_video_buffer *templat)
473 {
474 pipe_video_buffer tmpl = *templat;
475
476 //
477 // Check if the IHV requires texture array or opaque reference only allocations
478 //
479 bool bTextureArray = false;
480 if (codec->entrypoint == PIPE_VIDEO_ENTRYPOINT_BITSTREAM) {
481 struct d3d12_video_decoder *pD3D12Dec = (struct d3d12_video_decoder *) codec;
482
483 if (pD3D12Dec->m_ConfigDecoderSpecificFlags &
484 d3d12_video_decode_config_specific_flag_reference_only_textures_required)
485 tmpl.bind |= PIPE_BIND_VIDEO_DECODE_DPB;
486
487 bTextureArray = ((pD3D12Dec->m_ConfigDecoderSpecificFlags &
488 d3d12_video_decode_config_specific_flag_array_of_textures) == 0);
489
490 } else if (codec->entrypoint == PIPE_VIDEO_ENTRYPOINT_ENCODE) {
491 struct d3d12_video_encoder *pD3D12Enc = (struct d3d12_video_encoder *) codec;
492
493 if ((pD3D12Enc->m_currentEncodeCapabilities.m_SupportFlags &
494 D3D12_VIDEO_ENCODER_SUPPORT_FLAG_READABLE_RECONSTRUCTED_PICTURE_LAYOUT_AVAILABLE) == 0)
495 tmpl.bind |= PIPE_BIND_VIDEO_ENCODE_DPB;
496
497 bTextureArray = (pD3D12Enc->m_currentEncodeCapabilities.m_SupportFlags &
498 D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RECONSTRUCTED_FRAMES_REQUIRE_TEXTURE_ARRAYS);
499 }
500
501 if (bTextureArray)
502 return d3d12_video_create_dpb_buffer_texarray(codec, picture, &tmpl);
503 else
504 return d3d12_video_create_dpb_buffer_aot(codec, picture, &tmpl);
505 }
506
507 struct pipe_video_buffer*
d3d12_video_create_dpb_buffer_aot(struct pipe_video_codec * codec,struct pipe_picture_desc * picture,const struct pipe_video_buffer * templat)508 d3d12_video_create_dpb_buffer_aot(struct pipe_video_codec *codec,
509 struct pipe_picture_desc *picture,
510 const struct pipe_video_buffer *templat)
511 {
512 // For AOT, just return a new buffer with a new underlying pipe_resource
513 pipe_resource resource_creation_info = {};
514 return d3d12_video_buffer_create_impl(codec->context, templat, &resource_creation_info, d3d12_video_buffer_creation_mode::create_resource, NULL, 0);
515 }
516
517 struct pipe_video_buffer*
d3d12_video_create_dpb_buffer_texarray(struct pipe_video_codec * codec,struct pipe_picture_desc * picture,const struct pipe_video_buffer * templat)518 d3d12_video_create_dpb_buffer_texarray(struct pipe_video_codec *codec,
519 struct pipe_picture_desc *picture,
520 const struct pipe_video_buffer *templat)
521 {
522 d3d12_video_buffer* buf = NULL;
523 struct d3d12_video_encoder *pD3D12Enc = (struct d3d12_video_encoder *) codec;
524
525 // For texture array, keep a texture array pool of d3d12_video_encoder_get_current_max_dpb_capacity
526 // and keep track of used/unused subresource indices to return from the pool
527 if (!pD3D12Enc->m_pVideoTexArrayDPBPool)
528 {
529 pipe_resource resource_creation_info = {};
530 resource_creation_info.array_size = d3d12_video_encoder_get_current_max_dpb_capacity(pD3D12Enc);
531 assert(resource_creation_info.array_size <= 32); // uint32_t used as a usage bitmap into m_pVideoTexArrayDPBPool
532 buf = (d3d12_video_buffer*) d3d12_video_buffer_create_impl(codec->context, templat, &resource_creation_info, d3d12_video_buffer_creation_mode::create_resource, NULL, 0);
533 pD3D12Enc->m_pVideoTexArrayDPBPool = &buf->texture->base.b;
534 pD3D12Enc->m_spVideoTexArrayDPBPoolInUse = std::make_shared<uint32_t>();
535 }
536 else
537 {
538 buf = (d3d12_video_buffer*) d3d12_video_buffer_create_impl(codec->context, templat, pD3D12Enc->m_pVideoTexArrayDPBPool, d3d12_video_buffer_creation_mode::place_on_resource, NULL, 0);
539 }
540
541 // Set and increase refcount in buf object for usage in d3d12_video_buffer_destroy()
542 buf->m_spVideoTexArrayDPBPoolInUse = pD3D12Enc->m_spVideoTexArrayDPBPoolInUse;
543
544 ASSERTED bool bFoundEmptySlot = false;
545 for (unsigned i = 0; i < pD3D12Enc->m_pVideoTexArrayDPBPool->array_size; i++)
546 {
547 if (((*pD3D12Enc->m_spVideoTexArrayDPBPoolInUse) & (1 << i)) == 0)
548 {
549 buf->idx_texarray_slots = i;
550 (*pD3D12Enc->m_spVideoTexArrayDPBPoolInUse) |= (1 << buf->idx_texarray_slots); // Mark i-th bit as used
551 bFoundEmptySlot = true;
552 break;
553 }
554 }
555
556 assert(bFoundEmptySlot); // Possibly ran out of slots because the frontend is using more slots than we allocated in array_size when initializing m_pVideoTexArrayDPBPool
557 return &buf->base;
558 }
559