mesa: Allow override of GL version with environment variable
[mesa.git] / src / gallium / state_trackers / vdpau / output.c
1 /**************************************************************************
2 *
3 * Copyright 2010 Thomas Balling Sørensen.
4 * Copyright 2011 Christian König.
5 * All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sub license, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial portions
17 * of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
23 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 *
27 **************************************************************************/
28
29 #include <vdpau/vdpau.h>
30
31 #include "util/u_debug.h"
32 #include "util/u_memory.h"
33 #include "util/u_sampler.h"
34 #include "util/u_format.h"
35
36 #include "vdpau_private.h"
37
38 /**
39 * Create a VdpOutputSurface.
40 */
41 VdpStatus
42 vlVdpOutputSurfaceCreate(VdpDevice device,
43 VdpRGBAFormat rgba_format,
44 uint32_t width, uint32_t height,
45 VdpOutputSurface *surface)
46 {
47 struct pipe_context *pipe;
48 struct pipe_resource res_tmpl, *res;
49 struct pipe_sampler_view sv_templ;
50 struct pipe_surface surf_templ;
51
52 vlVdpOutputSurface *vlsurface = NULL;
53
54 VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Creating output surface\n");
55 if (!(width && height))
56 return VDP_STATUS_INVALID_SIZE;
57
58 vlVdpDevice *dev = vlGetDataHTAB(device);
59 if (!dev)
60 return VDP_STATUS_INVALID_HANDLE;
61
62 pipe = dev->context->pipe;
63 if (!pipe)
64 return VDP_STATUS_INVALID_HANDLE;
65
66 vlsurface = CALLOC(1, sizeof(vlVdpOutputSurface));
67 if (!vlsurface)
68 return VDP_STATUS_RESOURCES;
69
70 vlsurface->device = dev;
71
72 memset(&res_tmpl, 0, sizeof(res_tmpl));
73
74 res_tmpl.target = PIPE_TEXTURE_2D;
75 res_tmpl.format = FormatRGBAToPipe(rgba_format);
76 res_tmpl.width0 = width;
77 res_tmpl.height0 = height;
78 res_tmpl.depth0 = 1;
79 res_tmpl.array_size = 1;
80 res_tmpl.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;
81 res_tmpl.usage = PIPE_USAGE_STATIC;
82
83 res = pipe->screen->resource_create(pipe->screen, &res_tmpl);
84 if (!res) {
85 FREE(dev);
86 return VDP_STATUS_ERROR;
87 }
88
89 memset(&sv_templ, 0, sizeof(sv_templ));
90 u_sampler_view_default_template(&sv_templ, res, res->format);
91 vlsurface->sampler_view = pipe->create_sampler_view(pipe, res, &sv_templ);
92 if (!vlsurface->sampler_view) {
93 pipe_resource_reference(&res, NULL);
94 FREE(dev);
95 return VDP_STATUS_ERROR;
96 }
97
98 memset(&surf_templ, 0, sizeof(surf_templ));
99 surf_templ.format = res->format;
100 surf_templ.usage = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;
101 vlsurface->surface = pipe->create_surface(pipe, res, &surf_templ);
102 if (!vlsurface->surface) {
103 pipe_resource_reference(&res, NULL);
104 FREE(dev);
105 return VDP_STATUS_ERROR;
106 }
107
108 *surface = vlAddDataHTAB(vlsurface);
109 if (*surface == 0) {
110 pipe_resource_reference(&res, NULL);
111 FREE(dev);
112 return VDP_STATUS_ERROR;
113 }
114
115 pipe_resource_reference(&res, NULL);
116
117 return VDP_STATUS_OK;
118 }
119
120 /**
121 * Destroy a VdpOutputSurface.
122 */
123 VdpStatus
124 vlVdpOutputSurfaceDestroy(VdpOutputSurface surface)
125 {
126 vlVdpOutputSurface *vlsurface;
127
128 VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Destroying output surface\n");
129
130 vlsurface = vlGetDataHTAB(surface);
131 if (!vlsurface)
132 return VDP_STATUS_INVALID_HANDLE;
133
134 pipe_surface_reference(&vlsurface->surface, NULL);
135 pipe_sampler_view_reference(&vlsurface->sampler_view, NULL);
136
137 vlRemoveDataHTAB(surface);
138 FREE(vlsurface);
139
140 return VDP_STATUS_OK;
141 }
142
143 /**
144 * Retrieve the parameters used to create a VdpOutputSurface.
145 */
146 VdpStatus
147 vlVdpOutputSurfaceGetParameters(VdpOutputSurface surface,
148 VdpRGBAFormat *rgba_format,
149 uint32_t *width, uint32_t *height)
150 {
151 vlVdpOutputSurface *vlsurface;
152
153 VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Getting output surface parameters\n");
154
155 vlsurface = vlGetDataHTAB(surface);
156 if (!vlsurface)
157 return VDP_STATUS_INVALID_HANDLE;
158
159 *rgba_format = PipeToFormatRGBA(vlsurface->sampler_view->texture->format);
160 *width = vlsurface->sampler_view->texture->width0;
161 *height = vlsurface->sampler_view->texture->height0;
162
163 return VDP_STATUS_OK;
164 }
165
166 /**
167 * Copy image data from a VdpOutputSurface to application memory in the
168 * surface's native format.
169 */
170 VdpStatus
171 vlVdpOutputSurfaceGetBitsNative(VdpOutputSurface surface,
172 VdpRect const *source_rect,
173 void *const *destination_data,
174 uint32_t const *destination_pitches)
175 {
176 return VDP_STATUS_NO_IMPLEMENTATION;
177 }
178
179 /**
180 * Copy image data from application memory in the surface's native format to
181 * a VdpOutputSurface.
182 */
183 VdpStatus
184 vlVdpOutputSurfacePutBitsNative(VdpOutputSurface surface,
185 void const *const *source_data,
186 uint32_t const *source_pitches,
187 VdpRect const *destination_rect)
188 {
189 return VDP_STATUS_NO_IMPLEMENTATION;
190 }
191
192 /**
193 * Copy image data from application memory in a specific indexed format to
194 * a VdpOutputSurface.
195 */
196 VdpStatus
197 vlVdpOutputSurfacePutBitsIndexed(VdpOutputSurface surface,
198 VdpIndexedFormat source_indexed_format,
199 void const *const *source_data,
200 uint32_t const *source_pitch,
201 VdpRect const *destination_rect,
202 VdpColorTableFormat color_table_format,
203 void const *color_table)
204 {
205 vlVdpOutputSurface *vlsurface;
206 struct pipe_context *context;
207 struct vl_compositor *compositor;
208
209 enum pipe_format index_format;
210 enum pipe_format colortbl_format;
211
212 struct pipe_resource *res, res_tmpl;
213 struct pipe_sampler_view sv_tmpl;
214 struct pipe_sampler_view *sv_idx = NULL, *sv_tbl = NULL;
215
216 struct pipe_box box;
217 struct pipe_video_rect dst_rect;
218
219 VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Uploading indexed output surface\n");
220
221 vlsurface = vlGetDataHTAB(surface);
222 if (!vlsurface)
223 return VDP_STATUS_INVALID_HANDLE;
224
225 context = vlsurface->device->context->pipe;
226 compositor = &vlsurface->device->compositor;
227
228 index_format = FormatIndexedToPipe(source_indexed_format);
229 if (index_format == PIPE_FORMAT_NONE)
230 return VDP_STATUS_INVALID_INDEXED_FORMAT;
231
232 if (!source_data || !source_pitch)
233 return VDP_STATUS_INVALID_POINTER;
234
235 colortbl_format = FormatColorTableToPipe(color_table_format);
236 if (colortbl_format == PIPE_FORMAT_NONE)
237 return VDP_STATUS_INVALID_COLOR_TABLE_FORMAT;
238
239 if (!color_table)
240 return VDP_STATUS_INVALID_POINTER;
241
242 memset(&res_tmpl, 0, sizeof(res_tmpl));
243 res_tmpl.target = PIPE_TEXTURE_2D;
244 res_tmpl.format = index_format;
245
246 if (destination_rect) {
247 res_tmpl.width0 = abs(destination_rect->x0-destination_rect->x1);
248 res_tmpl.height0 = abs(destination_rect->y0-destination_rect->y1);
249 } else {
250 res_tmpl.width0 = vlsurface->surface->texture->width0;
251 res_tmpl.height0 = vlsurface->surface->texture->height0;
252 }
253 res_tmpl.depth0 = 1;
254 res_tmpl.array_size = 1;
255 res_tmpl.usage = PIPE_USAGE_STAGING;
256 res_tmpl.bind = PIPE_BIND_SAMPLER_VIEW;
257
258 res = context->screen->resource_create(context->screen, &res_tmpl);
259 if (!res)
260 goto error_resource;
261
262 box.x = box.y = box.z = 0;
263 box.width = res->width0;
264 box.height = res->height0;
265 box.depth = res->depth0;
266
267 context->transfer_inline_write(context, res, 0, PIPE_TRANSFER_WRITE, &box,
268 source_data[0], source_pitch[0],
269 source_pitch[0] * res->height0);
270
271 memset(&sv_tmpl, 0, sizeof(sv_tmpl));
272 u_sampler_view_default_template(&sv_tmpl, res, res->format);
273
274 sv_idx = context->create_sampler_view(context, res, &sv_tmpl);
275 pipe_resource_reference(&res, NULL);
276
277 if (!sv_idx)
278 goto error_resource;
279
280 memset(&res_tmpl, 0, sizeof(res_tmpl));
281 res_tmpl.target = PIPE_TEXTURE_1D;
282 res_tmpl.format = colortbl_format;
283 res_tmpl.width0 = 1 << util_format_get_component_bits(
284 index_format, UTIL_FORMAT_COLORSPACE_RGB, 0);
285 res_tmpl.height0 = 1;
286 res_tmpl.depth0 = 1;
287 res_tmpl.array_size = 1;
288 res_tmpl.usage = PIPE_USAGE_STAGING;
289 res_tmpl.bind = PIPE_BIND_SAMPLER_VIEW;
290
291 res = context->screen->resource_create(context->screen, &res_tmpl);
292 if (!res)
293 goto error_resource;
294
295 box.x = box.y = box.z = 0;
296 box.width = res->width0;
297 box.height = res->height0;
298 box.depth = res->depth0;
299
300 context->transfer_inline_write(context, res, 0, PIPE_TRANSFER_WRITE, &box, color_table,
301 util_format_get_stride(colortbl_format, res->width0), 0);
302
303 memset(&sv_tmpl, 0, sizeof(sv_tmpl));
304 u_sampler_view_default_template(&sv_tmpl, res, res->format);
305
306 sv_tbl = context->create_sampler_view(context, res, &sv_tmpl);
307 pipe_resource_reference(&res, NULL);
308
309 if (!sv_tbl)
310 goto error_resource;
311
312 vl_compositor_clear_layers(compositor);
313 vl_compositor_set_palette_layer(compositor, 0, sv_idx, sv_tbl, NULL, NULL, false);
314 vl_compositor_render(compositor, vlsurface->surface,
315 RectToPipe(destination_rect, &dst_rect), NULL, false);
316
317 pipe_sampler_view_reference(&sv_idx, NULL);
318 pipe_sampler_view_reference(&sv_tbl, NULL);
319
320 return VDP_STATUS_OK;
321
322 error_resource:
323 pipe_sampler_view_reference(&sv_idx, NULL);
324 pipe_sampler_view_reference(&sv_tbl, NULL);
325 return VDP_STATUS_RESOURCES;
326 }
327
328 /**
329 * Copy image data from application memory in a specific YCbCr format to
330 * a VdpOutputSurface.
331 */
332 VdpStatus
333 vlVdpOutputSurfacePutBitsYCbCr(VdpOutputSurface surface,
334 VdpYCbCrFormat source_ycbcr_format,
335 void const *const *source_data,
336 uint32_t const *source_pitches,
337 VdpRect const *destination_rect,
338 VdpCSCMatrix const *csc_matrix)
339 {
340 return VDP_STATUS_NO_IMPLEMENTATION;
341 }
342
343 static unsigned
344 BlendFactorToPipe(VdpOutputSurfaceRenderBlendFactor factor)
345 {
346 switch (factor) {
347 case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ZERO:
348 return PIPE_BLENDFACTOR_ZERO;
349 case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE:
350 return PIPE_BLENDFACTOR_ONE;
351 case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_SRC_COLOR:
352 return PIPE_BLENDFACTOR_SRC_COLOR;
353 case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_COLOR:
354 return PIPE_BLENDFACTOR_INV_SRC_COLOR;
355 case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_SRC_ALPHA:
356 return PIPE_BLENDFACTOR_SRC_ALPHA;
357 case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA:
358 return PIPE_BLENDFACTOR_INV_SRC_ALPHA;
359 case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_DST_ALPHA:
360 return PIPE_BLENDFACTOR_DST_ALPHA;
361 case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_DST_ALPHA:
362 return PIPE_BLENDFACTOR_INV_DST_ALPHA;
363 case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_DST_COLOR:
364 return PIPE_BLENDFACTOR_DST_COLOR;
365 case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_DST_COLOR:
366 return PIPE_BLENDFACTOR_INV_DST_COLOR;
367 case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_SRC_ALPHA_SATURATE:
368 return PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE;
369 case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_CONSTANT_COLOR:
370 return PIPE_BLENDFACTOR_CONST_COLOR;
371 case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR:
372 return PIPE_BLENDFACTOR_INV_CONST_COLOR;
373 case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_CONSTANT_ALPHA:
374 return PIPE_BLENDFACTOR_CONST_ALPHA;
375 case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA:
376 return PIPE_BLENDFACTOR_INV_CONST_ALPHA;
377 default:
378 assert(0);
379 return PIPE_BLENDFACTOR_ONE;
380 }
381 }
382
383 static unsigned
384 BlendEquationToPipe(VdpOutputSurfaceRenderBlendEquation equation)
385 {
386 switch (equation) {
387 case VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_SUBTRACT:
388 return PIPE_BLEND_SUBTRACT;
389 case VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_REVERSE_SUBTRACT:
390 return PIPE_BLEND_REVERSE_SUBTRACT;
391 case VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD:
392 return PIPE_BLEND_ADD;
393 case VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_MIN:
394 return PIPE_BLEND_MIN;
395 case VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_MAX:
396 return PIPE_BLEND_MAX;
397 default:
398 assert(0);
399 return PIPE_BLEND_ADD;
400 }
401 }
402
403 static void *
404 BlenderToPipe(struct pipe_context *context,
405 VdpOutputSurfaceRenderBlendState const *blend_state)
406 {
407 struct pipe_blend_state blend;
408
409 memset(&blend, 0, sizeof blend);
410 blend.independent_blend_enable = 0;
411
412 if (blend_state) {
413 blend.rt[0].blend_enable = 1;
414 blend.rt[0].rgb_src_factor = BlendFactorToPipe(blend_state->blend_factor_source_color);
415 blend.rt[0].rgb_dst_factor = BlendFactorToPipe(blend_state->blend_factor_destination_color);
416 blend.rt[0].alpha_src_factor = BlendFactorToPipe(blend_state->blend_factor_source_alpha);
417 blend.rt[0].alpha_dst_factor = BlendFactorToPipe(blend_state->blend_factor_destination_alpha);
418 blend.rt[0].rgb_func = BlendEquationToPipe(blend_state->blend_equation_color);
419 blend.rt[0].alpha_func = BlendEquationToPipe(blend_state->blend_equation_alpha);
420 } else {
421 blend.rt[0].blend_enable = 0;
422 }
423
424 blend.logicop_enable = 0;
425 blend.logicop_func = PIPE_LOGICOP_CLEAR;
426 blend.rt[0].colormask = PIPE_MASK_RGBA;
427 blend.dither = 0;
428
429 return context->create_blend_state(context, &blend);
430 }
431
432 /**
433 * Composite a sub-rectangle of a VdpOutputSurface into a sub-rectangle of
434 * another VdpOutputSurface; Output Surface object VdpOutputSurface.
435 */
436 VdpStatus
437 vlVdpOutputSurfaceRenderOutputSurface(VdpOutputSurface destination_surface,
438 VdpRect const *destination_rect,
439 VdpOutputSurface source_surface,
440 VdpRect const *source_rect,
441 VdpColor const *colors,
442 VdpOutputSurfaceRenderBlendState const *blend_state,
443 uint32_t flags)
444 {
445 vlVdpOutputSurface *dst_vlsurface;
446 vlVdpOutputSurface *src_vlsurface;
447
448 struct pipe_context *context;
449 struct vl_compositor *compositor;
450
451 struct pipe_video_rect src_rect;
452 struct pipe_video_rect dst_rect;
453
454 void *blend;
455
456 VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Composing output surfaces\n");
457
458 dst_vlsurface = vlGetDataHTAB(destination_surface);
459 if (!dst_vlsurface)
460 return VDP_STATUS_INVALID_HANDLE;
461
462 src_vlsurface = vlGetDataHTAB(source_surface);
463 if (!src_vlsurface)
464 return VDP_STATUS_INVALID_HANDLE;
465
466 if (dst_vlsurface->device != src_vlsurface->device)
467 return VDP_STATUS_HANDLE_DEVICE_MISMATCH;
468
469 context = dst_vlsurface->device->context->pipe;
470 compositor = &dst_vlsurface->device->compositor;
471
472 blend = BlenderToPipe(context, blend_state);
473
474 vl_compositor_clear_layers(compositor);
475 vl_compositor_set_layer_blend(compositor, 0, blend, false);
476 vl_compositor_set_rgba_layer(compositor, 0, src_vlsurface->sampler_view,
477 RectToPipe(source_rect, &src_rect), NULL);
478 vl_compositor_render(compositor, dst_vlsurface->surface,
479 RectToPipe(destination_rect, &dst_rect), NULL, false);
480
481 context->delete_blend_state(context, blend);
482
483 return VDP_STATUS_OK;
484 }
485
486 /**
487 * Composite a sub-rectangle of a VdpBitmapSurface into a sub-rectangle of
488 * a VdpOutputSurface; Output Surface object VdpOutputSurface.
489 */
490 VdpStatus
491 vlVdpOutputSurfaceRenderBitmapSurface(VdpOutputSurface destination_surface,
492 VdpRect const *destination_rect,
493 VdpBitmapSurface source_surface,
494 VdpRect const *source_rect,
495 VdpColor const *colors,
496 VdpOutputSurfaceRenderBlendState const *blend_state,
497 uint32_t flags)
498 {
499 return VDP_STATUS_NO_IMPLEMENTATION;
500 }