• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_resource.h"
26 #include "d3d12_video_dec.h"
27 #include "d3d12_residency.h"
28 
29 #include "util/format/u_format.h"
30 #include "util/u_inlines.h"
31 #include "util/u_memory.h"
32 #include "util/u_video.h"
33 #include "vl/vl_video_buffer.h"
34 #include "util/u_sampler.h"
35 #include "frontend/winsys_handle.h"
36 #include "d3d12_format.h"
37 #include "d3d12_screen.h"
38 
39 static struct pipe_video_buffer *
d3d12_video_buffer_create_impl(struct pipe_context * pipe,const struct pipe_video_buffer * tmpl,struct winsys_handle * handle,unsigned usage)40 d3d12_video_buffer_create_impl(struct pipe_context *pipe,
41                               const struct pipe_video_buffer *tmpl,
42                               struct winsys_handle *handle,
43                               unsigned usage)
44 {
45    assert(pipe);
46    assert(tmpl);
47 
48    ///
49    /// Initialize d3d12_video_buffer
50    ///
51 
52    // Not using new doesn't call ctor and the initializations in the class declaration are lost
53    struct d3d12_video_buffer *pD3D12VideoBuffer = new d3d12_video_buffer;
54 
55    // Fill base template
56    pD3D12VideoBuffer->base               = *tmpl;
57    pD3D12VideoBuffer->base.buffer_format = tmpl->buffer_format;
58    pD3D12VideoBuffer->base.context       = pipe;
59    pD3D12VideoBuffer->base.width         = tmpl->width;
60    pD3D12VideoBuffer->base.height        = tmpl->height;
61    pD3D12VideoBuffer->base.interlaced    = tmpl->interlaced;
62    pD3D12VideoBuffer->base.associated_data = nullptr;
63    pD3D12VideoBuffer->base.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET | PIPE_BIND_DISPLAY_TARGET | PIPE_BIND_CUSTOM;
64 
65    // Fill vtable
66    pD3D12VideoBuffer->base.destroy                     = d3d12_video_buffer_destroy;
67    pD3D12VideoBuffer->base.get_resources               = d3d12_video_buffer_resources;
68    pD3D12VideoBuffer->base.get_sampler_view_planes     = d3d12_video_buffer_get_sampler_view_planes;
69    pD3D12VideoBuffer->base.get_sampler_view_components = d3d12_video_buffer_get_sampler_view_components;
70    pD3D12VideoBuffer->base.get_surfaces                = d3d12_video_buffer_get_surfaces;
71    pD3D12VideoBuffer->base.destroy_associated_data     = d3d12_video_buffer_destroy_associated_data;
72 
73    struct pipe_resource templ;
74    memset(&templ, 0, sizeof(templ));
75    templ.target     = PIPE_TEXTURE_2D;
76    templ.bind       = pD3D12VideoBuffer->base.bind;
77    templ.format     = pD3D12VideoBuffer->base.buffer_format;
78    if (handle)
79    {
80       // YUV 4:2:0 formats in D3D12 always require multiple of 2 dimensions
81       // We must respect the input dimensions of the imported resource handle (e.g no extra aligning)
82       templ.width0     = align(pD3D12VideoBuffer->base.width, 2);
83       templ.height0    = align(pD3D12VideoBuffer->base.height, 2);
84    }
85    else
86    {
87       // When creating (e.g not importing) resources we allocate
88       // with a higher alignment to maximize HW compatibility
89       templ.width0     = align(pD3D12VideoBuffer->base.width, 2);
90       templ.height0    = align(pD3D12VideoBuffer->base.height, 16);
91    }
92    templ.depth0     = 1;
93    templ.array_size = 1;
94    templ.flags      = 0;
95 
96    // This calls d3d12_create_resource as the function ptr is set in d3d12_screen.resource_create
97    if(handle)
98    {
99       // WINSYS_HANDLE_TYPE_D3D12_RES implies taking ownership of the reference
100       if(handle->type == WINSYS_HANDLE_TYPE_D3D12_RES)
101          ((IUnknown *)handle->com_obj)->AddRef();
102       pD3D12VideoBuffer->texture = (struct d3d12_resource *) pipe->screen->resource_from_handle(pipe->screen, &templ, handle, usage);
103    }
104    else
105       pD3D12VideoBuffer->texture = (struct d3d12_resource *) pipe->screen->resource_create(pipe->screen, &templ);
106 
107    if (pD3D12VideoBuffer->texture == nullptr) {
108       debug_printf("[d3d12_video_buffer] d3d12_video_buffer_create - Call to resource_create() to create "
109                       "d3d12_resource failed\n");
110       goto failed;
111    }
112 
113    d3d12_promote_to_permanent_residency((struct d3d12_screen*) pipe->screen, pD3D12VideoBuffer->texture);
114 
115    pD3D12VideoBuffer->num_planes = util_format_get_num_planes(pD3D12VideoBuffer->texture->overall_format);
116    return &pD3D12VideoBuffer->base;
117 
118 failed:
119    d3d12_video_buffer_destroy((struct pipe_video_buffer *) pD3D12VideoBuffer);
120 
121    return nullptr;
122 }
123 
124 /**
125  * creates a video buffer from a handle
126  */
127 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)128 d3d12_video_buffer_from_handle(struct pipe_context *pipe,
129                                const struct pipe_video_buffer *tmpl,
130                                struct winsys_handle *handle,
131                                unsigned usage)
132 {
133    struct pipe_video_buffer updated_template = {};
134    if ((handle->format == PIPE_FORMAT_NONE) || (tmpl == nullptr) || (tmpl->buffer_format == PIPE_FORMAT_NONE) ||
135        (tmpl->width == 0) || (tmpl->height == 0)) {
136       ID3D12Resource *d3d12_res = nullptr;
137       if (handle->type == WINSYS_HANDLE_TYPE_D3D12_RES) {
138          d3d12_res = (ID3D12Resource *) handle->com_obj;
139       } else if (handle->type == WINSYS_HANDLE_TYPE_FD) {
140 #ifdef _WIN32
141          HANDLE d3d_handle = handle->handle;
142 #else
143          HANDLE d3d_handle = (HANDLE) (intptr_t) handle->handle;
144 #endif
145          if (FAILED(d3d12_screen(pipe->screen)->dev->OpenSharedHandle(d3d_handle, IID_PPV_ARGS(&d3d12_res)))) {
146             return NULL;
147          }
148       }
149       D3D12_RESOURCE_DESC res_desc = GetDesc(d3d12_res);
150       updated_template.width = res_desc.Width;
151       updated_template.height = res_desc.Height;
152       updated_template.buffer_format = d3d12_get_pipe_format(res_desc.Format);
153       handle->format = updated_template.buffer_format;
154 
155       // if passed an external com_ptr (e.g WINSYS_HANDLE_TYPE_D3D12_RES) do not release it
156       if (handle->type == WINSYS_HANDLE_TYPE_FD)
157          d3d12_res->Release();
158    } else {
159       updated_template = *tmpl;
160    }
161 
162    return d3d12_video_buffer_create_impl(pipe, &updated_template, handle, usage);
163 }
164 
165 /**
166  * creates a video buffer
167  */
168 struct pipe_video_buffer *
d3d12_video_buffer_create(struct pipe_context * pipe,const struct pipe_video_buffer * tmpl)169 d3d12_video_buffer_create(struct pipe_context *pipe, const struct pipe_video_buffer *tmpl)
170 {
171    return d3d12_video_buffer_create_impl(pipe, tmpl, NULL, 0);
172 }
173 
174 /**
175  * destroy this video buffer
176  */
177 void
d3d12_video_buffer_destroy(struct pipe_video_buffer * buffer)178 d3d12_video_buffer_destroy(struct pipe_video_buffer *buffer)
179 {
180    struct d3d12_video_buffer *pD3D12VideoBuffer = (struct d3d12_video_buffer *) buffer;
181 
182    // Destroy pD3D12VideoBuffer->texture (if any)
183    if (pD3D12VideoBuffer->texture) {
184       pipe_resource *pBaseResource = &pD3D12VideoBuffer->texture->base.b;
185       pipe_resource_reference(&pBaseResource, NULL);
186    }
187 
188    // Destroy associated data (if any)
189    if (pD3D12VideoBuffer->base.associated_data != nullptr) {
190       d3d12_video_buffer_destroy_associated_data(pD3D12VideoBuffer->base.associated_data);
191       // Set to nullptr after cleanup, no dangling pointers
192       pD3D12VideoBuffer->base.associated_data = nullptr;
193    }
194 
195    for (uint i = 0; i < pD3D12VideoBuffer->surfaces.size(); ++i) {
196       if (pD3D12VideoBuffer->surfaces[i] != NULL) {
197          pipe_surface_reference(&pD3D12VideoBuffer->surfaces[i], NULL);
198       }
199    }
200 
201    for (uint i = 0; i < pD3D12VideoBuffer->sampler_view_planes.size(); ++i) {
202       if (pD3D12VideoBuffer->sampler_view_planes[i] != NULL) {
203          pipe_sampler_view_reference(&pD3D12VideoBuffer->sampler_view_planes[i], NULL);
204       }
205    }
206 
207    for (uint i = 0; i < pD3D12VideoBuffer->sampler_view_components.size(); ++i) {
208       if (pD3D12VideoBuffer->sampler_view_components[i] != NULL) {
209          pipe_sampler_view_reference(&pD3D12VideoBuffer->sampler_view_components[i], NULL);
210       }
211    }
212 
213    delete pD3D12VideoBuffer;
214 }
215 
216 /*
217  * destroy the associated data
218  */
219 void
d3d12_video_buffer_destroy_associated_data(void * associated_data)220 d3d12_video_buffer_destroy_associated_data(void *associated_data)
221 { }
222 
223 /**
224  * get an individual surfaces for each plane
225  */
226 struct pipe_surface **
d3d12_video_buffer_get_surfaces(struct pipe_video_buffer * buffer)227 d3d12_video_buffer_get_surfaces(struct pipe_video_buffer *buffer)
228 {
229    assert(buffer);
230    struct d3d12_video_buffer *pD3D12VideoBuffer = (struct d3d12_video_buffer *) buffer;
231    struct pipe_context *      pipe              = pD3D12VideoBuffer->base.context;
232    struct pipe_surface        surface_template  = {};
233 
234    // Some video frameworks iterate over [0..VL_MAX_SURFACES) and ignore the nullptr entries
235    // So we have to null initialize the other surfaces not used from [num_planes..VL_MAX_SURFACES)
236    // Like in src/gallium/frontends/va/surface.c
237    pD3D12VideoBuffer->surfaces.resize(VL_MAX_SURFACES, nullptr);
238 
239    // pCurPlaneResource refers to the planar resource, not the overall resource.
240    // in d3d12_resource this is handled by having a linked list of planes with
241    // d3dRes->base.next ptr to next plane resource
242    // starting with the plane 0 being the overall resource
243    struct pipe_resource *pCurPlaneResource = &pD3D12VideoBuffer->texture->base.b;
244 
245    for (uint PlaneSlice = 0; PlaneSlice < pD3D12VideoBuffer->num_planes; ++PlaneSlice) {
246       if (!pD3D12VideoBuffer->surfaces[PlaneSlice]) {
247          memset(&surface_template, 0, sizeof(surface_template));
248          surface_template.format =
249             util_format_get_plane_format(pD3D12VideoBuffer->texture->overall_format, PlaneSlice);
250 
251          pD3D12VideoBuffer->surfaces[PlaneSlice] =
252             pipe->create_surface(pipe, pCurPlaneResource, &surface_template);
253 
254          if (!pD3D12VideoBuffer->surfaces[PlaneSlice]) {
255             goto error;
256          }
257       }
258       pCurPlaneResource = pCurPlaneResource->next;
259    }
260 
261    return pD3D12VideoBuffer->surfaces.data();
262 
263 error:
264    for (uint PlaneSlice = 0; PlaneSlice < pD3D12VideoBuffer->num_planes; ++PlaneSlice) {
265       pipe_surface_reference(&pD3D12VideoBuffer->surfaces[PlaneSlice], NULL);
266    }
267 
268    return nullptr;
269 }
270 
271 /**
272  * get an individual resource for each plane,
273  * only returns existing resources by reference
274  */
275 void
d3d12_video_buffer_resources(struct pipe_video_buffer * buffer,struct pipe_resource ** resources)276 d3d12_video_buffer_resources(struct pipe_video_buffer *buffer,
277                              struct pipe_resource **resources)
278 {
279    struct d3d12_video_buffer *pD3D12VideoBuffer = (struct d3d12_video_buffer *) buffer;
280    assert(pD3D12VideoBuffer);
281 
282    // pCurPlaneResource refers to the planar resource, not the overall resource.
283    // in d3d12_resource this is handled by having a linked list of planes with
284    // d3dRes->base.next ptr to next plane resource
285    // starting with the plane 0 being the overall resource
286    struct pipe_resource *pCurPlaneResource = &pD3D12VideoBuffer->texture->base.b;
287 
288    for (uint i = 0; i < pD3D12VideoBuffer->num_planes; ++i) {
289       assert(pCurPlaneResource); // the d3d12_resource has a linked list with the exact name of number of elements
290                                  // as planes
291 
292       resources[i] = pCurPlaneResource;
293       pCurPlaneResource = pCurPlaneResource->next;
294    }
295 }
296 
297 /**
298  * get an individual sampler view for each plane
299  */
300 struct pipe_sampler_view **
d3d12_video_buffer_get_sampler_view_planes(struct pipe_video_buffer * buffer)301 d3d12_video_buffer_get_sampler_view_planes(struct pipe_video_buffer *buffer)
302 {
303    assert(buffer);
304    struct d3d12_video_buffer *pD3D12VideoBuffer = (struct d3d12_video_buffer *) buffer;
305    struct pipe_context *      pipe              = pD3D12VideoBuffer->base.context;
306    struct pipe_sampler_view   samplerViewTemplate;
307 
308    // Some video frameworks iterate over [0..VL_MAX_SURFACES) and ignore the nullptr entries
309    // So we have to null initialize the other surfaces not used from [num_planes..VL_MAX_SURFACES)
310    // Like in src/gallium/frontends/vdpau/surface.c
311    pD3D12VideoBuffer->sampler_view_planes.resize(VL_MAX_SURFACES, nullptr);
312 
313    // pCurPlaneResource refers to the planar resource, not the overall resource.
314    // in d3d12_resource this is handled by having a linked list of planes with
315    // d3dRes->base.next ptr to next plane resource
316    // starting with the plane 0 being the overall resource
317    struct pipe_resource *pCurPlaneResource = &pD3D12VideoBuffer->texture->base.b;
318 
319    for (uint i = 0; i < pD3D12VideoBuffer->num_planes; ++i) {
320       if (!pD3D12VideoBuffer->sampler_view_planes[i]) {
321          assert(pCurPlaneResource);   // the d3d12_resource has a linked list with the exact name of number of elements
322                                       // as planes
323 
324          memset(&samplerViewTemplate, 0, sizeof(samplerViewTemplate));
325          u_sampler_view_default_template(&samplerViewTemplate, pCurPlaneResource, pCurPlaneResource->format);
326 
327          pD3D12VideoBuffer->sampler_view_planes[i] =
328             pipe->create_sampler_view(pipe, pCurPlaneResource, &samplerViewTemplate);
329 
330          if (!pD3D12VideoBuffer->sampler_view_planes[i]) {
331             goto error;
332          }
333       }
334 
335       pCurPlaneResource = pCurPlaneResource->next;
336    }
337 
338    return pD3D12VideoBuffer->sampler_view_planes.data();
339 
340 error:
341    for (uint i = 0; i < pD3D12VideoBuffer->num_planes; ++i) {
342       pipe_sampler_view_reference(&pD3D12VideoBuffer->sampler_view_planes[i], NULL);
343    }
344 
345    return nullptr;
346 }
347 
348 /**
349  * get an individual sampler view for each component
350  */
351 struct pipe_sampler_view **
d3d12_video_buffer_get_sampler_view_components(struct pipe_video_buffer * buffer)352 d3d12_video_buffer_get_sampler_view_components(struct pipe_video_buffer *buffer)
353 {
354    assert(buffer);
355    struct d3d12_video_buffer *pD3D12VideoBuffer = (struct d3d12_video_buffer *) buffer;
356    struct pipe_context *      pipe              = pD3D12VideoBuffer->base.context;
357    struct pipe_sampler_view   samplerViewTemplate;
358 
359    // pCurPlaneResource refers to the planar resource, not the overall resource.
360    // in d3d12_resource this is handled by having a linked list of planes with
361    // d3dRes->base.next ptr to next plane resource
362    // starting with the plane 0 being the overall resource
363    struct pipe_resource *pCurPlaneResource = &pD3D12VideoBuffer->texture->base.b;
364 
365    const uint32_t MAX_NUM_COMPONENTS = 4; // ie. RGBA formats
366    // At the end of the loop, "component" will have the total number of items valid in sampler_view_components
367    // since component can end up being <= MAX_NUM_COMPONENTS, we assume MAX_NUM_COMPONENTS first and then resize/adjust to
368    // fit the container size pD3D12VideoBuffer->sampler_view_components to the actual components number
369    pD3D12VideoBuffer->sampler_view_components.resize(MAX_NUM_COMPONENTS, nullptr);
370    uint component = 0;
371 
372    for (uint i = 0; i < pD3D12VideoBuffer->num_planes; ++i) {
373       // For example num_components would be 1 for the Y plane (R8 in NV12), 2 for the UV plane (R8G8 in NV12)
374       unsigned num_components = util_format_get_nr_components(pCurPlaneResource->format);
375 
376       for (uint j = 0; j < num_components; ++j, ++component) {
377 
378          if (!pD3D12VideoBuffer->sampler_view_components[component]) {
379             memset(&samplerViewTemplate, 0, sizeof(samplerViewTemplate));
380             u_sampler_view_default_template(&samplerViewTemplate, pCurPlaneResource, pCurPlaneResource->format);
381             samplerViewTemplate.swizzle_r = samplerViewTemplate.swizzle_g = samplerViewTemplate.swizzle_b =
382                PIPE_SWIZZLE_X + j;
383             samplerViewTemplate.swizzle_a = PIPE_SWIZZLE_1;
384 
385             pD3D12VideoBuffer->sampler_view_components[component] =
386                pipe->create_sampler_view(pipe, pCurPlaneResource, &samplerViewTemplate);
387             if (!pD3D12VideoBuffer->sampler_view_components[component]) {
388                goto error;
389             }
390          }
391       }
392 
393       pCurPlaneResource = pCurPlaneResource->next;
394    }
395 
396    // Adjust size to fit component <= VL_NUM_COMPONENTS
397    pD3D12VideoBuffer->sampler_view_components.resize(component);
398 
399    return pD3D12VideoBuffer->sampler_view_components.data();
400 
401 error:
402    for (uint i = 0; i < pD3D12VideoBuffer->num_planes; ++i) {
403       pipe_sampler_view_reference(&pD3D12VideoBuffer->sampler_view_components[i], NULL);
404    }
405 
406    return nullptr;
407 }
408