1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 2010 LunarG Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 * Chia-I Wu <olv@lunarg.com>
26 */
27
28 #include "main/errors.h"
29 #include "main/texobj.h"
30 #include "main/teximage.h"
31 #include "util/u_inlines.h"
32 #include "util/format/u_format.h"
33 #include "st_cb_eglimage.h"
34 #include "st_cb_fbo.h"
35 #include "st_context.h"
36 #include "st_texture.h"
37 #include "st_format.h"
38 #include "st_manager.h"
39 #include "st_sampler_view.h"
40 #include "util/u_surface.h"
41
42 static bool
is_format_supported(struct pipe_screen * screen,enum pipe_format format,unsigned nr_samples,unsigned nr_storage_samples,unsigned usage,bool * native_supported)43 is_format_supported(struct pipe_screen *screen, enum pipe_format format,
44 unsigned nr_samples, unsigned nr_storage_samples,
45 unsigned usage, bool *native_supported)
46 {
47 bool supported = screen->is_format_supported(screen, format, PIPE_TEXTURE_2D,
48 nr_samples, nr_storage_samples,
49 usage);
50 *native_supported = supported;
51
52 /* for sampling, some formats can be emulated.. it doesn't matter that
53 * the surface will have a format that the driver can't cope with because
54 * we'll give it sampler view formats that it can deal with and generate
55 * a shader variant that converts.
56 */
57 if ((usage == PIPE_BIND_SAMPLER_VIEW) && !supported) {
58 switch (format) {
59 case PIPE_FORMAT_IYUV:
60 supported = screen->is_format_supported(screen, PIPE_FORMAT_R8_UNORM,
61 PIPE_TEXTURE_2D, nr_samples,
62 nr_storage_samples, usage);
63 break;
64 case PIPE_FORMAT_NV12:
65 supported = screen->is_format_supported(screen, PIPE_FORMAT_R8_UNORM,
66 PIPE_TEXTURE_2D, nr_samples,
67 nr_storage_samples, usage) &&
68 screen->is_format_supported(screen, PIPE_FORMAT_R8G8_UNORM,
69 PIPE_TEXTURE_2D, nr_samples,
70 nr_storage_samples, usage);
71 break;
72 case PIPE_FORMAT_P010:
73 case PIPE_FORMAT_P012:
74 case PIPE_FORMAT_P016:
75 supported = screen->is_format_supported(screen, PIPE_FORMAT_R16_UNORM,
76 PIPE_TEXTURE_2D, nr_samples,
77 nr_storage_samples, usage) &&
78 screen->is_format_supported(screen, PIPE_FORMAT_R16G16_UNORM,
79 PIPE_TEXTURE_2D, nr_samples,
80 nr_storage_samples, usage);
81 break;
82 case PIPE_FORMAT_YUYV:
83 supported = screen->is_format_supported(screen, PIPE_FORMAT_RG88_UNORM,
84 PIPE_TEXTURE_2D, nr_samples,
85 nr_storage_samples, usage) &&
86 screen->is_format_supported(screen, PIPE_FORMAT_BGRA8888_UNORM,
87 PIPE_TEXTURE_2D, nr_samples,
88 nr_storage_samples, usage);
89 break;
90 case PIPE_FORMAT_UYVY:
91 supported = screen->is_format_supported(screen, PIPE_FORMAT_RG88_UNORM,
92 PIPE_TEXTURE_2D, nr_samples,
93 nr_storage_samples, usage) &&
94 screen->is_format_supported(screen, PIPE_FORMAT_RGBA8888_UNORM,
95 PIPE_TEXTURE_2D, nr_samples,
96 nr_storage_samples, usage);
97 break;
98 case PIPE_FORMAT_AYUV:
99 supported = screen->is_format_supported(screen, PIPE_FORMAT_RGBA8888_UNORM,
100 PIPE_TEXTURE_2D, nr_samples,
101 nr_storage_samples, usage);
102 break;
103 case PIPE_FORMAT_XYUV:
104 supported = screen->is_format_supported(screen, PIPE_FORMAT_RGBX8888_UNORM,
105 PIPE_TEXTURE_2D, nr_samples,
106 nr_storage_samples, usage);
107 break;
108 default:
109 break;
110 }
111 }
112
113 return supported;
114 }
115
116 static bool
is_nv12_as_r8_g8b8_supported(struct pipe_screen * screen,struct st_egl_image * out,unsigned usage,bool * native_supported)117 is_nv12_as_r8_g8b8_supported(struct pipe_screen *screen, struct st_egl_image *out,
118 unsigned usage, bool *native_supported)
119 {
120 if (out->format == PIPE_FORMAT_NV12 &&
121 out->texture->format == PIPE_FORMAT_R8_G8B8_420_UNORM &&
122 screen->is_format_supported(screen, PIPE_FORMAT_R8_G8B8_420_UNORM,
123 PIPE_TEXTURE_2D,
124 out->texture->nr_samples,
125 out->texture->nr_storage_samples,
126 usage)) {
127 *native_supported = false;
128 return true;
129 }
130
131 return false;
132 }
133
134
135 /**
136 * Return the gallium texture of an EGLImage.
137 */
138 static bool
st_get_egl_image(struct gl_context * ctx,GLeglImageOES image_handle,unsigned usage,const char * error,struct st_egl_image * out,bool * native_supported)139 st_get_egl_image(struct gl_context *ctx, GLeglImageOES image_handle,
140 unsigned usage, const char *error, struct st_egl_image *out,
141 bool *native_supported)
142 {
143 struct st_context *st = st_context(ctx);
144 struct pipe_screen *screen = st->pipe->screen;
145 struct st_manager *smapi =
146 (struct st_manager *) st->iface.st_context_private;
147
148 if (!smapi || !smapi->get_egl_image)
149 return false;
150
151 memset(out, 0, sizeof(*out));
152 if (!smapi->get_egl_image(smapi, (void *) image_handle, out)) {
153 /* image_handle does not refer to a valid EGL image object */
154 _mesa_error(ctx, GL_INVALID_VALUE, "%s(image handle not found)", error);
155 return false;
156 }
157
158 if (!is_nv12_as_r8_g8b8_supported(screen, out, usage, native_supported) &&
159 !is_format_supported(screen, out->format, out->texture->nr_samples,
160 out->texture->nr_storage_samples, usage,
161 native_supported)) {
162 /* unable to specify a texture object using the specified EGL image */
163 pipe_resource_reference(&out->texture, NULL);
164 _mesa_error(ctx, GL_INVALID_OPERATION, "%s(format not supported)", error);
165 return false;
166 }
167
168 return true;
169 }
170
171 /**
172 * Return the base format just like _mesa_base_fbo_format does.
173 */
174 static GLenum
st_pipe_format_to_base_format(enum pipe_format format)175 st_pipe_format_to_base_format(enum pipe_format format)
176 {
177 GLenum base_format;
178
179 if (util_format_is_depth_or_stencil(format)) {
180 if (util_format_is_depth_and_stencil(format)) {
181 base_format = GL_DEPTH_STENCIL;
182 }
183 else {
184 if (format == PIPE_FORMAT_S8_UINT)
185 base_format = GL_STENCIL_INDEX;
186 else
187 base_format = GL_DEPTH_COMPONENT;
188 }
189 }
190 else {
191 /* is this enough? */
192 if (util_format_has_alpha(format))
193 base_format = GL_RGBA;
194 else
195 base_format = GL_RGB;
196 }
197
198 return base_format;
199 }
200
201 static void
st_egl_image_target_renderbuffer_storage(struct gl_context * ctx,struct gl_renderbuffer * rb,GLeglImageOES image_handle)202 st_egl_image_target_renderbuffer_storage(struct gl_context *ctx,
203 struct gl_renderbuffer *rb,
204 GLeglImageOES image_handle)
205 {
206 struct st_renderbuffer *strb = st_renderbuffer(rb);
207 struct st_egl_image stimg;
208 bool native_supported;
209
210 if (st_get_egl_image(ctx, image_handle, PIPE_BIND_RENDER_TARGET,
211 "glEGLImageTargetRenderbufferStorage",
212 &stimg, &native_supported)) {
213 struct pipe_context *pipe = st_context(ctx)->pipe;
214 struct pipe_surface *ps, surf_tmpl;
215
216 u_surface_default_template(&surf_tmpl, stimg.texture);
217 surf_tmpl.format = stimg.format;
218 surf_tmpl.u.tex.level = stimg.level;
219 surf_tmpl.u.tex.first_layer = stimg.layer;
220 surf_tmpl.u.tex.last_layer = stimg.layer;
221 ps = pipe->create_surface(pipe, stimg.texture, &surf_tmpl);
222 pipe_resource_reference(&stimg.texture, NULL);
223
224 if (!ps)
225 return;
226
227 strb->Base.Format = st_pipe_format_to_mesa_format(ps->format);
228 strb->Base._BaseFormat = st_pipe_format_to_base_format(ps->format);
229 strb->Base.InternalFormat = strb->Base._BaseFormat;
230
231 st_set_ws_renderbuffer_surface(strb, ps);
232 pipe_surface_reference(&ps, NULL);
233 }
234 }
235
236 static void
st_bind_egl_image(struct gl_context * ctx,struct gl_texture_object * texObj,struct gl_texture_image * texImage,struct st_egl_image * stimg,bool tex_storage,bool native_supported)237 st_bind_egl_image(struct gl_context *ctx,
238 struct gl_texture_object *texObj,
239 struct gl_texture_image *texImage,
240 struct st_egl_image *stimg,
241 bool tex_storage,
242 bool native_supported)
243 {
244 struct st_context *st = st_context(ctx);
245 struct st_texture_object *stObj;
246 struct st_texture_image *stImage;
247 GLenum internalFormat;
248 mesa_format texFormat;
249
250 /* map pipe format to base format */
251 if (util_format_get_component_bits(stimg->format,
252 UTIL_FORMAT_COLORSPACE_RGB, 3) > 0)
253 internalFormat = GL_RGBA;
254 else
255 internalFormat = GL_RGB;
256
257 stObj = st_texture_object(texObj);
258 stImage = st_texture_image(texImage);
259
260 /* switch to surface based */
261 if (!stObj->surface_based) {
262 _mesa_clear_texture_object(ctx, texObj, NULL);
263 stObj->surface_based = GL_TRUE;
264 }
265
266 /* TODO RequiredTextureImageUnits should probably be reset back
267 * to 1 somewhere if different texture is bound??
268 */
269 if (!native_supported) {
270 switch (stimg->format) {
271 case PIPE_FORMAT_NV12:
272 if (stimg->texture->format == PIPE_FORMAT_R8_G8B8_420_UNORM) {
273 texFormat = MESA_FORMAT_R8G8B8X8_UNORM;
274 texObj->RequiredTextureImageUnits = 1;
275 } else {
276 texFormat = MESA_FORMAT_R_UNORM8;
277 texObj->RequiredTextureImageUnits = 2;
278 }
279 break;
280 case PIPE_FORMAT_P010:
281 case PIPE_FORMAT_P012:
282 case PIPE_FORMAT_P016:
283 texFormat = MESA_FORMAT_R_UNORM16;
284 texObj->RequiredTextureImageUnits = 2;
285 break;
286 case PIPE_FORMAT_IYUV:
287 texFormat = MESA_FORMAT_R_UNORM8;
288 texObj->RequiredTextureImageUnits = 3;
289 break;
290 case PIPE_FORMAT_YUYV:
291 case PIPE_FORMAT_UYVY:
292 texFormat = MESA_FORMAT_RG_UNORM8;
293 texObj->RequiredTextureImageUnits = 2;
294 break;
295 case PIPE_FORMAT_AYUV:
296 texFormat = MESA_FORMAT_R8G8B8A8_UNORM;
297 internalFormat = GL_RGBA;
298 texObj->RequiredTextureImageUnits = 1;
299 break;
300 case PIPE_FORMAT_XYUV:
301 texFormat = MESA_FORMAT_R8G8B8X8_UNORM;
302 texObj->RequiredTextureImageUnits = 1;
303 break;
304 default:
305 unreachable("unexpected emulated format");
306 break;
307 }
308 } else {
309 texFormat = st_pipe_format_to_mesa_format(stimg->format);
310 /* Use previously derived internalformat as specified by
311 * EXT_EGL_image_storage.
312 */
313 if (tex_storage && texObj->Target == GL_TEXTURE_2D
314 && stimg->internalformat) {
315 internalFormat = stimg->internalformat;
316 if (internalFormat == GL_NONE) {
317 _mesa_error(ctx, GL_INVALID_OPERATION, __func__);
318 return;
319 }
320 }
321 }
322 assert(texFormat != MESA_FORMAT_NONE);
323
324
325 /* Minify texture size based on level set on the EGLImage. */
326 uint32_t width = u_minify(stimg->texture->width0, stimg->level);
327 uint32_t height = u_minify(stimg->texture->height0, stimg->level);
328
329 _mesa_init_teximage_fields(ctx, texImage, width, height,
330 1, 0, internalFormat, texFormat);
331
332 pipe_resource_reference(&stObj->pt, stimg->texture);
333 st_texture_release_all_sampler_views(st, stObj);
334 pipe_resource_reference(&stImage->pt, stObj->pt);
335 if (st->pipe->screen->resource_changed)
336 st->pipe->screen->resource_changed(st->pipe->screen, stImage->pt);
337
338 stObj->surface_format = stimg->format;
339 stObj->level_override = stimg->level;
340 stObj->layer_override = stimg->layer;
341
342 _mesa_dirty_texobj(ctx, texObj);
343 }
344
345 static void
st_egl_image_target_texture_2d(struct gl_context * ctx,GLenum target,struct gl_texture_object * texObj,struct gl_texture_image * texImage,GLeglImageOES image_handle)346 st_egl_image_target_texture_2d(struct gl_context *ctx, GLenum target,
347 struct gl_texture_object *texObj,
348 struct gl_texture_image *texImage,
349 GLeglImageOES image_handle)
350 {
351 struct st_egl_image stimg;
352 bool native_supported;
353
354 if (!st_get_egl_image(ctx, image_handle, PIPE_BIND_SAMPLER_VIEW,
355 "glEGLImageTargetTexture2D", &stimg,
356 &native_supported))
357 return;
358
359 st_bind_egl_image(ctx, texObj, texImage, &stimg,
360 target != GL_TEXTURE_EXTERNAL_OES,
361 native_supported);
362 pipe_resource_reference(&stimg.texture, NULL);
363 }
364
365 static void
st_egl_image_target_tex_storage(struct gl_context * ctx,GLenum target,struct gl_texture_object * texObj,struct gl_texture_image * texImage,GLeglImageOES image_handle)366 st_egl_image_target_tex_storage(struct gl_context *ctx, GLenum target,
367 struct gl_texture_object *texObj,
368 struct gl_texture_image *texImage,
369 GLeglImageOES image_handle)
370 {
371 struct st_egl_image stimg;
372 bool native_supported;
373
374 if (!st_get_egl_image(ctx, image_handle, PIPE_BIND_SAMPLER_VIEW,
375 "glEGLImageTargetTexture2D", &stimg,
376 &native_supported))
377 return;
378
379 st_bind_egl_image(ctx, texObj, texImage, &stimg, true, native_supported);
380 pipe_resource_reference(&stimg.texture, NULL);
381 }
382
383 void
st_init_eglimage_functions(struct dd_function_table * functions)384 st_init_eglimage_functions(struct dd_function_table *functions)
385 {
386 functions->EGLImageTargetTexture2D = st_egl_image_target_texture_2d;
387 functions->EGLImageTargetTexStorage = st_egl_image_target_tex_storage;
388 functions->EGLImageTargetRenderbufferStorage = st_egl_image_target_renderbuffer_storage;
389 }
390