• 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 
36 /**
37  * creates a video buffer
38  */
39 struct pipe_video_buffer *
d3d12_video_buffer_create(struct pipe_context * pipe,const struct pipe_video_buffer * tmpl)40 d3d12_video_buffer_create(struct pipe_context *pipe, const struct pipe_video_buffer *tmpl)
41 {
42    assert(pipe);
43    assert(tmpl);
44 
45    ///
46    /// Initialize d3d12_video_buffer
47    ///
48 
49 
50    if (!(tmpl->buffer_format == PIPE_FORMAT_NV12)) {
51       debug_printf("[d3d12_video_buffer] buffer_format is only supported as PIPE_FORMAT_NV12.\n");
52       return nullptr;
53    }
54 
55    if (!(pipe_format_to_chroma_format(tmpl->buffer_format) == PIPE_VIDEO_CHROMA_FORMAT_420)) {
56       debug_printf(
57          "[d3d12_video_buffer] tmpl->buffer_format only supported as a PIPE_VIDEO_CHROMA_FORMAT_420 format.\n");
58       return nullptr;
59    }
60 
61    // Not using new doesn't call ctor and the initializations in the class declaration are lost
62    struct d3d12_video_buffer *pD3D12VideoBuffer = new d3d12_video_buffer;
63 
64    // Fill base template
65    pD3D12VideoBuffer->base               = *tmpl;
66    pD3D12VideoBuffer->base.buffer_format = tmpl->buffer_format;
67    pD3D12VideoBuffer->base.context       = pipe;
68    pD3D12VideoBuffer->base.width         = tmpl->width;
69    pD3D12VideoBuffer->base.height        = tmpl->height;
70    pD3D12VideoBuffer->base.interlaced    = tmpl->interlaced;
71    pD3D12VideoBuffer->base.associated_data = nullptr;
72    pD3D12VideoBuffer->base.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET | PIPE_BIND_DISPLAY_TARGET;
73 
74    // Fill vtable
75    pD3D12VideoBuffer->base.destroy                     = d3d12_video_buffer_destroy;
76    pD3D12VideoBuffer->base.get_sampler_view_planes     = d3d12_video_buffer_get_sampler_view_planes;
77    pD3D12VideoBuffer->base.get_sampler_view_components = d3d12_video_buffer_get_sampler_view_components;
78    pD3D12VideoBuffer->base.get_surfaces                = d3d12_video_buffer_get_surfaces;
79    pD3D12VideoBuffer->base.destroy_associated_data     = d3d12_video_buffer_destroy_associated_data;
80 
81    struct pipe_resource templ;
82    memset(&templ, 0, sizeof(templ));
83    templ.target     = PIPE_TEXTURE_2D;
84    templ.bind       = pD3D12VideoBuffer->base.bind;
85    templ.format     = pD3D12VideoBuffer->base.buffer_format;
86    // YUV 4:2:0 formats in D3D12 need to have multiple of 2 dimensions
87    templ.width0     = align(pD3D12VideoBuffer->base.width, 2);
88    templ.height0    = align(pD3D12VideoBuffer->base.height, 2);
89    templ.depth0     = 1;
90    templ.array_size = 1;
91    templ.flags      = 0;
92 
93    // This calls d3d12_create_resource as the function ptr is set in d3d12_screen.resource_create
94    pD3D12VideoBuffer->texture = (struct d3d12_resource *) pipe->screen->resource_create(pipe->screen, &templ);
95    d3d12_promote_to_permanent_residency((struct d3d12_screen*) pipe->screen, pD3D12VideoBuffer->texture);
96 
97    if (pD3D12VideoBuffer->texture == nullptr) {
98       debug_printf("[d3d12_video_buffer] d3d12_video_buffer_create - Call to resource_create() to create "
99                       "d3d12_resource failed\n");
100       goto failed;
101    }
102 
103    pD3D12VideoBuffer->num_planes = util_format_get_num_planes(pD3D12VideoBuffer->texture->overall_format);
104    assert(pD3D12VideoBuffer->num_planes == 2);
105    return &pD3D12VideoBuffer->base;
106 
107 failed:
108    d3d12_video_buffer_destroy((struct pipe_video_buffer *) pD3D12VideoBuffer);
109 
110    return nullptr;
111 }
112 
113 /**
114  * destroy this video buffer
115  */
116 void
d3d12_video_buffer_destroy(struct pipe_video_buffer * buffer)117 d3d12_video_buffer_destroy(struct pipe_video_buffer *buffer)
118 {
119    struct d3d12_video_buffer *pD3D12VideoBuffer = (struct d3d12_video_buffer *) buffer;
120 
121    // Destroy pD3D12VideoBuffer->texture (if any)
122    if (pD3D12VideoBuffer->texture) {
123       pipe_resource *pBaseResource = &pD3D12VideoBuffer->texture->base.b;
124       pipe_resource_reference(&pBaseResource, NULL);
125    }
126 
127    // Destroy associated data (if any)
128    if (pD3D12VideoBuffer->base.associated_data != nullptr) {
129       d3d12_video_buffer_destroy_associated_data(pD3D12VideoBuffer->base.associated_data);
130       // Set to nullptr after cleanup, no dangling pointers
131       pD3D12VideoBuffer->base.associated_data = nullptr;
132    }
133 
134    // Destroy (if any) codec where the associated data came from
135    if (pD3D12VideoBuffer->base.codec != nullptr) {
136       d3d12_video_decoder_destroy(pD3D12VideoBuffer->base.codec);
137       // Set to nullptr after cleanup, no dangling pointers
138       pD3D12VideoBuffer->base.codec = nullptr;
139    }
140 
141    for (uint i = 0; i < pD3D12VideoBuffer->surfaces.size(); ++i) {
142       if (pD3D12VideoBuffer->surfaces[i] != NULL) {
143          pipe_surface_reference(&pD3D12VideoBuffer->surfaces[i], NULL);
144       }
145    }
146 
147    for (uint i = 0; i < pD3D12VideoBuffer->sampler_view_planes.size(); ++i) {
148       if (pD3D12VideoBuffer->sampler_view_planes[i] != NULL) {
149          pipe_sampler_view_reference(&pD3D12VideoBuffer->sampler_view_planes[i], NULL);
150       }
151    }
152 
153    for (uint i = 0; i < pD3D12VideoBuffer->sampler_view_components.size(); ++i) {
154       if (pD3D12VideoBuffer->sampler_view_components[i] != NULL) {
155          pipe_sampler_view_reference(&pD3D12VideoBuffer->sampler_view_components[i], NULL);
156       }
157    }
158 
159    delete pD3D12VideoBuffer;
160 }
161 
162 /*
163  * destroy the associated data
164  */
165 void
d3d12_video_buffer_destroy_associated_data(void * associated_data)166 d3d12_video_buffer_destroy_associated_data(void *associated_data)
167 { }
168 
169 /**
170  * get an individual surfaces for each plane
171  */
172 struct pipe_surface **
d3d12_video_buffer_get_surfaces(struct pipe_video_buffer * buffer)173 d3d12_video_buffer_get_surfaces(struct pipe_video_buffer *buffer)
174 {
175    assert(buffer);
176    struct d3d12_video_buffer *pD3D12VideoBuffer = (struct d3d12_video_buffer *) buffer;
177    struct pipe_context *      pipe              = pD3D12VideoBuffer->base.context;
178    struct pipe_surface        surface_template  = {};
179 
180    // Some video frameworks iterate over [0..VL_MAX_SURFACES) and ignore the nullptr entries
181    // So we have to null initialize the other surfaces not used from [num_planes..VL_MAX_SURFACES)
182    // Like in src/gallium/frontends/va/surface.c
183    pD3D12VideoBuffer->surfaces.resize(VL_MAX_SURFACES, nullptr);
184 
185    // pCurPlaneResource refers to the planar resource, not the overall resource.
186    // in d3d12_resource this is handled by having a linked list of planes with
187    // d3dRes->base.next ptr to next plane resource
188    // starting with the plane 0 being the overall resource
189    struct pipe_resource *pCurPlaneResource = &pD3D12VideoBuffer->texture->base.b;
190 
191    for (uint PlaneSlice = 0; PlaneSlice < pD3D12VideoBuffer->num_planes; ++PlaneSlice) {
192       if (!pD3D12VideoBuffer->surfaces[PlaneSlice]) {
193          memset(&surface_template, 0, sizeof(surface_template));
194          surface_template.format =
195             util_format_get_plane_format(pD3D12VideoBuffer->texture->overall_format, PlaneSlice);
196 
197          pD3D12VideoBuffer->surfaces[PlaneSlice] =
198             pipe->create_surface(pipe, pCurPlaneResource, &surface_template);
199 
200          if (!pD3D12VideoBuffer->surfaces[PlaneSlice]) {
201             goto error;
202          }
203       }
204       pCurPlaneResource = pCurPlaneResource->next;
205    }
206 
207    return pD3D12VideoBuffer->surfaces.data();
208 
209 error:
210    for (uint PlaneSlice = 0; PlaneSlice < pD3D12VideoBuffer->num_planes; ++PlaneSlice) {
211       pipe_surface_reference(&pD3D12VideoBuffer->surfaces[PlaneSlice], NULL);
212    }
213 
214    return nullptr;
215 }
216 
217 /**
218  * get an individual sampler view for each plane
219  */
220 struct pipe_sampler_view **
d3d12_video_buffer_get_sampler_view_planes(struct pipe_video_buffer * buffer)221 d3d12_video_buffer_get_sampler_view_planes(struct pipe_video_buffer *buffer)
222 {
223    assert(buffer);
224    struct d3d12_video_buffer *pD3D12VideoBuffer = (struct d3d12_video_buffer *) buffer;
225    struct pipe_context *      pipe              = pD3D12VideoBuffer->base.context;
226    struct pipe_sampler_view   samplerViewTemplate;
227 
228    // Some video frameworks iterate over [0..VL_MAX_SURFACES) and ignore the nullptr entries
229    // So we have to null initialize the other surfaces not used from [num_planes..VL_MAX_SURFACES)
230    // Like in src/gallium/frontends/vdpau/surface.c
231    pD3D12VideoBuffer->sampler_view_planes.resize(VL_MAX_SURFACES, nullptr);
232 
233    // pCurPlaneResource refers to the planar resource, not the overall resource.
234    // in d3d12_resource this is handled by having a linked list of planes with
235    // d3dRes->base.next ptr to next plane resource
236    // starting with the plane 0 being the overall resource
237    struct pipe_resource *pCurPlaneResource = &pD3D12VideoBuffer->texture->base.b;
238 
239    for (uint i = 0; i < pD3D12VideoBuffer->num_planes; ++i) {
240       if (!pD3D12VideoBuffer->sampler_view_planes[i]) {
241          assert(pCurPlaneResource);   // the d3d12_resource has a linked list with the exact name of number of elements
242                                       // as planes
243 
244          memset(&samplerViewTemplate, 0, sizeof(samplerViewTemplate));
245          u_sampler_view_default_template(&samplerViewTemplate, pCurPlaneResource, pCurPlaneResource->format);
246 
247          pD3D12VideoBuffer->sampler_view_planes[i] =
248             pipe->create_sampler_view(pipe, pCurPlaneResource, &samplerViewTemplate);
249 
250          if (!pD3D12VideoBuffer->sampler_view_planes[i]) {
251             goto error;
252          }
253       }
254 
255       pCurPlaneResource = pCurPlaneResource->next;
256    }
257 
258    return pD3D12VideoBuffer->sampler_view_planes.data();
259 
260 error:
261    for (uint i = 0; i < pD3D12VideoBuffer->num_planes; ++i) {
262       pipe_sampler_view_reference(&pD3D12VideoBuffer->sampler_view_planes[i], NULL);
263    }
264 
265    return nullptr;
266 }
267 
268 /**
269  * get an individual sampler view for each component
270  */
271 struct pipe_sampler_view **
d3d12_video_buffer_get_sampler_view_components(struct pipe_video_buffer * buffer)272 d3d12_video_buffer_get_sampler_view_components(struct pipe_video_buffer *buffer)
273 {
274    assert(buffer);
275    struct d3d12_video_buffer *pD3D12VideoBuffer = (struct d3d12_video_buffer *) buffer;
276    struct pipe_context *      pipe              = pD3D12VideoBuffer->base.context;
277    struct pipe_sampler_view   samplerViewTemplate;
278 
279    // pCurPlaneResource refers to the planar resource, not the overall resource.
280    // in d3d12_resource this is handled by having a linked list of planes with
281    // d3dRes->base.next ptr to next plane resource
282    // starting with the plane 0 being the overall resource
283    struct pipe_resource *pCurPlaneResource = &pD3D12VideoBuffer->texture->base.b;
284 
285    // At the end of the loop, "component" will have the total number of items valid in sampler_view_components
286    // since component can end up being <= VL_NUM_COMPONENTS, we assume VL_NUM_COMPONENTS first and then resize/adjust to
287    // fit the container size pD3D12VideoBuffer->sampler_view_components to the actual components number
288    pD3D12VideoBuffer->sampler_view_components.resize(VL_NUM_COMPONENTS, nullptr);
289    uint component = 0;
290 
291    for (uint i = 0; i < pD3D12VideoBuffer->num_planes; ++i) {
292       // For example num_components would be 1 for the Y plane (R8 in NV12), 2 for the UV plane (R8G8 in NV12)
293       unsigned num_components = util_format_get_nr_components(pCurPlaneResource->format);
294 
295       for (uint j = 0; j < num_components; ++j, ++component) {
296          assert(component < VL_NUM_COMPONENTS);
297 
298          if (!pD3D12VideoBuffer->sampler_view_components[component]) {
299             memset(&samplerViewTemplate, 0, sizeof(samplerViewTemplate));
300             u_sampler_view_default_template(&samplerViewTemplate, pCurPlaneResource, pCurPlaneResource->format);
301             samplerViewTemplate.swizzle_r = samplerViewTemplate.swizzle_g = samplerViewTemplate.swizzle_b =
302                PIPE_SWIZZLE_X + j;
303             samplerViewTemplate.swizzle_a = PIPE_SWIZZLE_1;
304 
305             pD3D12VideoBuffer->sampler_view_components[component] =
306                pipe->create_sampler_view(pipe, pCurPlaneResource, &samplerViewTemplate);
307             if (!pD3D12VideoBuffer->sampler_view_components[component]) {
308                goto error;
309             }
310          }
311       }
312 
313       pCurPlaneResource = pCurPlaneResource->next;
314    }
315 
316    // Adjust size to fit component <= VL_NUM_COMPONENTS
317    pD3D12VideoBuffer->sampler_view_components.resize(component);
318 
319    return pD3D12VideoBuffer->sampler_view_components.data();
320 
321 error:
322    for (uint i = 0; i < pD3D12VideoBuffer->num_planes; ++i) {
323       pipe_sampler_view_reference(&pD3D12VideoBuffer->sampler_view_components[i], NULL);
324    }
325 
326    return nullptr;
327 }
328