xref: /aosp_15_r20/external/mesa3d/src/gallium/drivers/d3d12/d3d12_video_buffer.cpp (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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