i965: Allow forcing miptree->array_layout = ALL_SLICES_AT_EACH_LOD
[mesa.git] / src / mesa / drivers / dri / i965 / intel_tex_image.c
1
2 #include "main/glheader.h"
3 #include "main/macros.h"
4 #include "main/mtypes.h"
5 #include "main/enums.h"
6 #include "main/bufferobj.h"
7 #include "main/context.h"
8 #include "main/formats.h"
9 #include "main/image.h"
10 #include "main/pbo.h"
11 #include "main/renderbuffer.h"
12 #include "main/texcompress.h"
13 #include "main/texgetimage.h"
14 #include "main/texobj.h"
15 #include "main/teximage.h"
16 #include "main/texstore.h"
17
18 #include "drivers/common/meta.h"
19
20 #include "intel_mipmap_tree.h"
21 #include "intel_buffer_objects.h"
22 #include "intel_batchbuffer.h"
23 #include "intel_tex.h"
24 #include "intel_blit.h"
25 #include "intel_fbo.h"
26 #include "intel_image.h"
27
28 #include "brw_context.h"
29
30 #define FILE_DEBUG_FLAG DEBUG_TEXTURE
31
32 /* Work back from the specified level of the image to the baselevel and create a
33 * miptree of that size.
34 */
35 struct intel_mipmap_tree *
36 intel_miptree_create_for_teximage(struct brw_context *brw,
37 struct intel_texture_object *intelObj,
38 struct intel_texture_image *intelImage,
39 bool expect_accelerated_upload)
40 {
41 GLuint lastLevel;
42 int width, height, depth;
43 GLuint i;
44
45 intel_miptree_get_dimensions_for_image(&intelImage->base.Base,
46 &width, &height, &depth);
47
48 DBG("%s\n", __FUNCTION__);
49
50 /* Figure out image dimensions at start level. */
51 for (i = intelImage->base.Base.Level; i > 0; i--) {
52 width <<= 1;
53 if (height != 1)
54 height <<= 1;
55 if (depth != 1)
56 depth <<= 1;
57 }
58
59 /* Guess a reasonable value for lastLevel. This is probably going
60 * to be wrong fairly often and might mean that we have to look at
61 * resizable buffers, or require that buffers implement lazy
62 * pagetable arrangements.
63 */
64 if ((intelObj->base.Sampler.MinFilter == GL_NEAREST ||
65 intelObj->base.Sampler.MinFilter == GL_LINEAR) &&
66 intelImage->base.Base.Level == 0 &&
67 !intelObj->base.GenerateMipmap) {
68 lastLevel = 0;
69 } else {
70 lastLevel = _mesa_get_tex_max_num_levels(intelObj->base.Target,
71 width, height, depth) - 1;
72 }
73
74 return intel_miptree_create(brw,
75 intelObj->base.Target,
76 intelImage->base.Base.TexFormat,
77 0,
78 lastLevel,
79 width,
80 height,
81 depth,
82 expect_accelerated_upload,
83 intelImage->base.Base.NumSamples,
84 INTEL_MIPTREE_TILING_ANY,
85 false);
86 }
87
88 /* XXX: Do this for TexSubImage also:
89 */
90 static bool
91 try_pbo_upload(struct gl_context *ctx,
92 struct gl_texture_image *image,
93 const struct gl_pixelstore_attrib *unpack,
94 GLenum format, GLenum type, const void *pixels)
95 {
96 struct intel_texture_image *intelImage = intel_texture_image(image);
97 struct brw_context *brw = brw_context(ctx);
98 struct intel_buffer_object *pbo = intel_buffer_object(unpack->BufferObj);
99 GLuint src_offset;
100 drm_intel_bo *src_buffer;
101
102 if (!_mesa_is_bufferobj(unpack->BufferObj))
103 return false;
104
105 DBG("trying pbo upload\n");
106
107 if (ctx->_ImageTransferState || unpack->SkipPixels || unpack->SkipRows) {
108 DBG("%s: image transfer\n", __FUNCTION__);
109 return false;
110 }
111
112 ctx->Driver.AllocTextureImageBuffer(ctx, image);
113
114 if (!intelImage->mt) {
115 DBG("%s: no miptree\n", __FUNCTION__);
116 return false;
117 }
118
119 if (!_mesa_format_matches_format_and_type(intelImage->mt->format,
120 format, type, false)) {
121 DBG("%s: format mismatch (upload to %s with format 0x%x, type 0x%x)\n",
122 __FUNCTION__, _mesa_get_format_name(intelImage->mt->format),
123 format, type);
124 return false;
125 }
126
127 if (image->TexObject->Target == GL_TEXTURE_1D_ARRAY ||
128 image->TexObject->Target == GL_TEXTURE_2D_ARRAY) {
129 DBG("%s: no support for array textures\n", __FUNCTION__);
130 return false;
131 }
132
133 int src_stride =
134 _mesa_image_row_stride(unpack, image->Width, format, type);
135
136 /* note: potential 64-bit ptr to 32-bit int cast */
137 src_offset = (GLuint) (unsigned long) pixels;
138 src_buffer = intel_bufferobj_buffer(brw, pbo,
139 src_offset, src_stride * image->Height);
140
141 struct intel_mipmap_tree *pbo_mt =
142 intel_miptree_create_for_bo(brw,
143 src_buffer,
144 intelImage->mt->format,
145 src_offset,
146 image->Width, image->Height,
147 src_stride);
148 if (!pbo_mt)
149 return false;
150
151 if (!intel_miptree_blit(brw,
152 pbo_mt, 0, 0,
153 0, 0, false,
154 intelImage->mt, image->Level, image->Face,
155 0, 0, false,
156 image->Width, image->Height, GL_COPY)) {
157 DBG("%s: blit failed\n", __FUNCTION__);
158 intel_miptree_release(&pbo_mt);
159 return false;
160 }
161
162 intel_miptree_release(&pbo_mt);
163
164 DBG("%s: success\n", __FUNCTION__);
165 return true;
166 }
167
168 static void
169 intelTexImage(struct gl_context * ctx,
170 GLuint dims,
171 struct gl_texture_image *texImage,
172 GLenum format, GLenum type, const void *pixels,
173 const struct gl_pixelstore_attrib *unpack)
174 {
175 bool ok;
176
177 DBG("%s mesa_format %s target %s format %s type %s level %d %dx%dx%d\n",
178 __FUNCTION__, _mesa_get_format_name(texImage->TexFormat),
179 _mesa_lookup_enum_by_nr(texImage->TexObject->Target),
180 _mesa_lookup_enum_by_nr(format), _mesa_lookup_enum_by_nr(type),
181 texImage->Level, texImage->Width, texImage->Height, texImage->Depth);
182
183 ok = intel_texsubimage_tiled_memcpy(ctx, dims, texImage,
184 0, 0, 0, /*x,y,z offsets*/
185 texImage->Width,
186 texImage->Height,
187 texImage->Depth,
188 format, type, pixels, unpack,
189 true /*for_glTexImage*/);
190 if (ok)
191 return;
192
193 /* Attempt to use the blitter for PBO image uploads.
194 */
195 if (dims <= 2 &&
196 try_pbo_upload(ctx, texImage, unpack, format, type, pixels)) {
197 return;
198 }
199
200 DBG("%s: upload image %dx%dx%d pixels %p\n",
201 __FUNCTION__, texImage->Width, texImage->Height, texImage->Depth,
202 pixels);
203
204 _mesa_store_teximage(ctx, dims, texImage,
205 format, type, pixels, unpack);
206 }
207
208
209 /**
210 * Binds a BO to a texture image, as if it was uploaded by glTexImage2D().
211 *
212 * Used for GLX_EXT_texture_from_pixmap and EGL image extensions,
213 */
214 static void
215 intel_set_texture_image_bo(struct gl_context *ctx,
216 struct gl_texture_image *image,
217 drm_intel_bo *bo,
218 GLenum target,
219 GLenum internalFormat,
220 mesa_format format,
221 uint32_t offset,
222 GLuint width, GLuint height,
223 GLuint pitch,
224 GLuint tile_x, GLuint tile_y)
225 {
226 struct brw_context *brw = brw_context(ctx);
227 struct intel_texture_image *intel_image = intel_texture_image(image);
228 struct gl_texture_object *texobj = image->TexObject;
229 struct intel_texture_object *intel_texobj = intel_texture_object(texobj);
230 uint32_t draw_x, draw_y;
231
232 _mesa_init_teximage_fields(&brw->ctx, image,
233 width, height, 1,
234 0, internalFormat, format);
235
236 ctx->Driver.FreeTextureImageBuffer(ctx, image);
237
238 intel_image->mt = intel_miptree_create_for_bo(brw, bo, image->TexFormat,
239 0, width, height, pitch);
240 if (intel_image->mt == NULL)
241 return;
242 intel_image->mt->target = target;
243 intel_image->mt->total_width = width;
244 intel_image->mt->total_height = height;
245 intel_image->mt->level[0].slice[0].x_offset = tile_x;
246 intel_image->mt->level[0].slice[0].y_offset = tile_y;
247
248 intel_miptree_get_tile_offsets(intel_image->mt, 0, 0, &draw_x, &draw_y);
249
250 /* From "OES_EGL_image" error reporting. We report GL_INVALID_OPERATION
251 * for EGL images from non-tile aligned sufaces in gen4 hw and earlier which has
252 * trouble resolving back to destination image due to alignment issues.
253 */
254 if (!brw->has_surface_tile_offset &&
255 (draw_x != 0 || draw_y != 0)) {
256 _mesa_error(ctx, GL_INVALID_OPERATION, __func__);
257 intel_miptree_release(&intel_image->mt);
258 return;
259 }
260
261 intel_texobj->needs_validate = true;
262
263 intel_image->mt->offset = offset;
264 assert(pitch % intel_image->mt->cpp == 0);
265 intel_image->base.RowStride = pitch / intel_image->mt->cpp;
266
267 /* Immediately validate the image to the object. */
268 intel_miptree_reference(&intel_texobj->mt, intel_image->mt);
269 }
270
271 void
272 intelSetTexBuffer2(__DRIcontext *pDRICtx, GLint target,
273 GLint texture_format,
274 __DRIdrawable *dPriv)
275 {
276 struct gl_framebuffer *fb = dPriv->driverPrivate;
277 struct brw_context *brw = pDRICtx->driverPrivate;
278 struct gl_context *ctx = &brw->ctx;
279 struct intel_renderbuffer *rb;
280 struct gl_texture_object *texObj;
281 struct gl_texture_image *texImage;
282 int level = 0, internalFormat = 0;
283 mesa_format texFormat = MESA_FORMAT_NONE;
284
285 texObj = _mesa_get_current_tex_object(ctx, target);
286
287 if (!texObj)
288 return;
289
290 if (dPriv->lastStamp != dPriv->dri2.stamp ||
291 !pDRICtx->driScreenPriv->dri2.useInvalidate)
292 intel_update_renderbuffers(pDRICtx, dPriv);
293
294 rb = intel_get_renderbuffer(fb, BUFFER_FRONT_LEFT);
295 /* If the miptree isn't set, then intel_update_renderbuffers was unable
296 * to get the BO for the drawable from the window system.
297 */
298 if (!rb || !rb->mt)
299 return;
300
301 if (rb->mt->cpp == 4) {
302 if (texture_format == __DRI_TEXTURE_FORMAT_RGB) {
303 internalFormat = GL_RGB;
304 texFormat = MESA_FORMAT_B8G8R8X8_UNORM;
305 }
306 else {
307 internalFormat = GL_RGBA;
308 texFormat = MESA_FORMAT_B8G8R8A8_UNORM;
309 }
310 } else if (rb->mt->cpp == 2) {
311 internalFormat = GL_RGB;
312 texFormat = MESA_FORMAT_B5G6R5_UNORM;
313 }
314
315 _mesa_lock_texture(&brw->ctx, texObj);
316 texImage = _mesa_get_tex_image(ctx, texObj, target, level);
317 intel_miptree_make_shareable(brw, rb->mt);
318 intel_set_texture_image_bo(ctx, texImage, rb->mt->bo, target,
319 internalFormat, texFormat, 0,
320 rb->Base.Base.Width,
321 rb->Base.Base.Height,
322 rb->mt->pitch,
323 0, 0);
324 _mesa_unlock_texture(&brw->ctx, texObj);
325 }
326
327 static GLboolean
328 intel_bind_renderbuffer_tex_image(struct gl_context *ctx,
329 struct gl_renderbuffer *rb,
330 struct gl_texture_image *image)
331 {
332 struct intel_renderbuffer *irb = intel_renderbuffer(rb);
333 struct intel_texture_image *intel_image = intel_texture_image(image);
334 struct gl_texture_object *texobj = image->TexObject;
335 struct intel_texture_object *intel_texobj = intel_texture_object(texobj);
336
337 /* We can only handle RB allocated with AllocRenderbufferStorage, or
338 * window-system renderbuffers.
339 */
340 assert(!rb->TexImage);
341
342 if (!irb->mt)
343 return false;
344
345 _mesa_lock_texture(ctx, texobj);
346 _mesa_init_teximage_fields(ctx, image,
347 rb->Width, rb->Height, 1,
348 0, rb->InternalFormat, rb->Format);
349 image->NumSamples = rb->NumSamples;
350
351 intel_miptree_reference(&intel_image->mt, irb->mt);
352
353 /* Immediately validate the image to the object. */
354 intel_miptree_reference(&intel_texobj->mt, intel_image->mt);
355
356 intel_texobj->needs_validate = true;
357 _mesa_unlock_texture(ctx, texobj);
358
359 return true;
360 }
361
362 void
363 intelSetTexBuffer(__DRIcontext *pDRICtx, GLint target, __DRIdrawable *dPriv)
364 {
365 /* The old interface didn't have the format argument, so copy our
366 * implementation's behavior at the time.
367 */
368 intelSetTexBuffer2(pDRICtx, target, __DRI_TEXTURE_FORMAT_RGBA, dPriv);
369 }
370
371 static void
372 intel_image_target_texture_2d(struct gl_context *ctx, GLenum target,
373 struct gl_texture_object *texObj,
374 struct gl_texture_image *texImage,
375 GLeglImageOES image_handle)
376 {
377 struct brw_context *brw = brw_context(ctx);
378 __DRIscreen *screen;
379 __DRIimage *image;
380
381 screen = brw->intelScreen->driScrnPriv;
382 image = screen->dri2.image->lookupEGLImage(screen, image_handle,
383 screen->loaderPrivate);
384 if (image == NULL)
385 return;
386
387 /**
388 * Images originating via EGL_EXT_image_dma_buf_import can be used only
389 * with GL_OES_EGL_image_external only.
390 */
391 if (image->dma_buf_imported && target != GL_TEXTURE_EXTERNAL_OES) {
392 _mesa_error(ctx, GL_INVALID_OPERATION,
393 "glEGLImageTargetTexture2DOES(dma buffers can be used with "
394 "GL_OES_EGL_image_external only");
395 return;
396 }
397
398 if (target == GL_TEXTURE_EXTERNAL_OES && !image->dma_buf_imported) {
399 _mesa_error(ctx, GL_INVALID_OPERATION,
400 "glEGLImageTargetTexture2DOES(external target is enabled only "
401 "for images created with EGL_EXT_image_dma_buf_import");
402 return;
403 }
404
405 /* Disallow depth/stencil textures: we don't have a way to pass the
406 * separate stencil miptree of a GL_DEPTH_STENCIL texture through.
407 */
408 if (image->has_depthstencil) {
409 _mesa_error(ctx, GL_INVALID_OPERATION, __func__);
410 return;
411 }
412
413 intel_set_texture_image_bo(ctx, texImage, image->bo,
414 target, image->internal_format,
415 image->format, image->offset,
416 image->width, image->height,
417 image->pitch,
418 image->tile_x, image->tile_y);
419 }
420
421 static bool
422 blit_texture_to_pbo(struct gl_context *ctx,
423 GLenum format, GLenum type,
424 GLvoid * pixels, struct gl_texture_image *texImage)
425 {
426 struct intel_texture_image *intelImage = intel_texture_image(texImage);
427 struct brw_context *brw = brw_context(ctx);
428 const struct gl_pixelstore_attrib *pack = &ctx->Pack;
429 struct intel_buffer_object *dst = intel_buffer_object(pack->BufferObj);
430 GLuint dst_offset;
431 drm_intel_bo *dst_buffer;
432 GLenum target = texImage->TexObject->Target;
433
434 /* Check if we can use GPU blit to copy from the hardware texture
435 * format to the user's format/type.
436 * Note that GL's pixel transfer ops don't apply to glGetTexImage()
437 */
438
439 if (!_mesa_format_matches_format_and_type(intelImage->mt->format, format,
440 type, false))
441 {
442 perf_debug("%s: unsupported format, fallback to CPU mapping for PBO\n",
443 __FUNCTION__);
444
445 return false;
446 }
447
448 if (ctx->_ImageTransferState) {
449 perf_debug("%s: bad transfer state, fallback to CPU mapping for PBO\n",
450 __FUNCTION__);
451 return false;
452 }
453
454 if (pack->SwapBytes || pack->LsbFirst) {
455 perf_debug("%s: unsupported pack swap params\n",
456 __FUNCTION__);
457 return false;
458 }
459
460 if (target == GL_TEXTURE_1D_ARRAY ||
461 target == GL_TEXTURE_2D_ARRAY ||
462 target == GL_TEXTURE_CUBE_MAP_ARRAY ||
463 target == GL_TEXTURE_3D) {
464 perf_debug("%s: no support for multiple slices, fallback to CPU mapping "
465 "for PBO\n", __FUNCTION__);
466 return false;
467 }
468
469 int dst_stride = _mesa_image_row_stride(pack, texImage->Width, format, type);
470 bool dst_flip = false;
471 /* Mesa flips the dst_stride for ctx->Pack.Invert, our mt must have a
472 * normal dst_stride.
473 */
474 struct gl_pixelstore_attrib uninverted_pack = *pack;
475 if (ctx->Pack.Invert) {
476 dst_stride = -dst_stride;
477 dst_flip = true;
478 uninverted_pack.Invert = false;
479 }
480 dst_offset = (GLintptr) pixels;
481 dst_offset += _mesa_image_offset(2, &uninverted_pack, texImage->Width,
482 texImage->Height, format, type, 0, 0, 0);
483 dst_buffer = intel_bufferobj_buffer(brw, dst, dst_offset,
484 texImage->Height * dst_stride);
485
486 struct intel_mipmap_tree *pbo_mt =
487 intel_miptree_create_for_bo(brw,
488 dst_buffer,
489 intelImage->mt->format,
490 dst_offset,
491 texImage->Width, texImage->Height,
492 dst_stride);
493
494 if (!pbo_mt)
495 return false;
496
497 if (!intel_miptree_blit(brw,
498 intelImage->mt, texImage->Level, texImage->Face,
499 0, 0, false,
500 pbo_mt, 0, 0,
501 0, 0, dst_flip,
502 texImage->Width, texImage->Height, GL_COPY))
503 return false;
504
505 intel_miptree_release(&pbo_mt);
506
507 return true;
508 }
509
510 static void
511 intel_get_tex_image(struct gl_context *ctx,
512 GLenum format, GLenum type, GLvoid *pixels,
513 struct gl_texture_image *texImage) {
514 DBG("%s\n", __FUNCTION__);
515
516 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
517 /* Using PBOs, so try the BLT based path. */
518 if (blit_texture_to_pbo(ctx, format, type, pixels, texImage))
519 return;
520
521 }
522
523 _mesa_meta_GetTexImage(ctx, format, type, pixels, texImage);
524
525 DBG("%s - DONE\n", __FUNCTION__);
526 }
527
528 void
529 intelInitTextureImageFuncs(struct dd_function_table *functions)
530 {
531 functions->TexImage = intelTexImage;
532 functions->EGLImageTargetTexture2D = intel_image_target_texture_2d;
533 functions->BindRenderbufferTexImage = intel_bind_renderbuffer_tex_image;
534 functions->GetTexImage = intel_get_tex_image;
535 }