Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4358 | Serge | 1 | /************************************************************************** |
2 | * |
||
3 | * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas. |
||
4 | * All Rights Reserved. |
||
5 | * |
||
6 | * Permission is hereby granted, free of charge, to any person obtaining a |
||
7 | * copy of this software and associated documentation files (the |
||
8 | * "Software"), to deal in the Software without restriction, including |
||
9 | * without limitation the rights to use, copy, modify, merge, publish, |
||
10 | * distribute, sub license, and/or sell copies of the Software, and to |
||
11 | * permit persons to whom the Software is furnished to do so, subject to |
||
12 | * the following conditions: |
||
13 | * |
||
14 | * The above copyright notice and this permission notice (including the |
||
15 | * next paragraph) shall be included in all copies or substantial portions |
||
16 | * of the Software. |
||
17 | * |
||
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
||
19 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
||
20 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. |
||
21 | * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR |
||
22 | * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
||
23 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
||
24 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||
25 | * |
||
26 | **************************************************************************/ |
||
27 | |||
28 | |||
29 | #include "main/enums.h" |
||
30 | #include "main/imports.h" |
||
31 | #include "main/macros.h" |
||
32 | #include "main/mtypes.h" |
||
33 | #include "main/fbobject.h" |
||
34 | #include "main/framebuffer.h" |
||
35 | #include "main/renderbuffer.h" |
||
36 | #include "main/context.h" |
||
37 | #include "main/teximage.h" |
||
38 | #include "main/image.h" |
||
39 | |||
40 | #include "swrast/swrast.h" |
||
41 | #include "drivers/common/meta.h" |
||
42 | |||
43 | #include "intel_batchbuffer.h" |
||
44 | #include "intel_buffers.h" |
||
45 | #include "intel_blit.h" |
||
46 | #include "intel_fbo.h" |
||
47 | #include "intel_mipmap_tree.h" |
||
48 | #include "intel_regions.h" |
||
49 | #include "intel_tex.h" |
||
50 | #include "brw_context.h" |
||
51 | |||
52 | #define FILE_DEBUG_FLAG DEBUG_FBO |
||
53 | |||
54 | /** |
||
55 | * Create a new framebuffer object. |
||
56 | */ |
||
57 | static struct gl_framebuffer * |
||
58 | intel_new_framebuffer(struct gl_context * ctx, GLuint name) |
||
59 | { |
||
60 | /* Only drawable state in intel_framebuffer at this time, just use Mesa's |
||
61 | * class |
||
62 | */ |
||
63 | return _mesa_new_framebuffer(ctx, name); |
||
64 | } |
||
65 | |||
66 | |||
67 | /** Called by gl_renderbuffer::Delete() */ |
||
68 | static void |
||
69 | intel_delete_renderbuffer(struct gl_context *ctx, struct gl_renderbuffer *rb) |
||
70 | { |
||
71 | struct intel_renderbuffer *irb = intel_renderbuffer(rb); |
||
72 | |||
73 | ASSERT(irb); |
||
74 | |||
75 | intel_miptree_release(&irb->mt); |
||
76 | |||
77 | _mesa_delete_renderbuffer(ctx, rb); |
||
78 | } |
||
79 | |||
80 | /** |
||
81 | * \see dd_function_table::MapRenderbuffer |
||
82 | */ |
||
83 | static void |
||
84 | intel_map_renderbuffer(struct gl_context *ctx, |
||
85 | struct gl_renderbuffer *rb, |
||
86 | GLuint x, GLuint y, GLuint w, GLuint h, |
||
87 | GLbitfield mode, |
||
88 | GLubyte **out_map, |
||
89 | GLint *out_stride) |
||
90 | { |
||
91 | struct brw_context *brw = brw_context(ctx); |
||
92 | struct swrast_renderbuffer *srb = (struct swrast_renderbuffer *)rb; |
||
93 | struct intel_renderbuffer *irb = intel_renderbuffer(rb); |
||
94 | void *map; |
||
95 | int stride; |
||
96 | |||
97 | if (srb->Buffer) { |
||
98 | /* this is a malloc'd renderbuffer (accum buffer), not an irb */ |
||
99 | GLint bpp = _mesa_get_format_bytes(rb->Format); |
||
100 | GLint rowStride = srb->RowStride; |
||
101 | *out_map = (GLubyte *) srb->Buffer + y * rowStride + x * bpp; |
||
102 | *out_stride = rowStride; |
||
103 | return; |
||
104 | } |
||
105 | |||
106 | intel_prepare_render(brw); |
||
107 | |||
108 | /* For a window-system renderbuffer, we need to flip the mapping we receive |
||
109 | * upside-down. So we need to ask for a rectangle on flipped vertically, and |
||
110 | * we then return a pointer to the bottom of it with a negative stride. |
||
111 | */ |
||
112 | if (rb->Name == 0) { |
||
113 | y = rb->Height - y - h; |
||
114 | } |
||
115 | |||
116 | intel_miptree_map(brw, irb->mt, irb->mt_level, irb->mt_layer, |
||
117 | x, y, w, h, mode, &map, &stride); |
||
118 | |||
119 | if (rb->Name == 0) { |
||
120 | map += (h - 1) * stride; |
||
121 | stride = -stride; |
||
122 | } |
||
123 | |||
124 | DBG("%s: rb %d (%s) mt mapped: (%d, %d) (%dx%d) -> %p/%d\n", |
||
125 | __FUNCTION__, rb->Name, _mesa_get_format_name(rb->Format), |
||
126 | x, y, w, h, map, stride); |
||
127 | |||
128 | *out_map = map; |
||
129 | *out_stride = stride; |
||
130 | } |
||
131 | |||
132 | /** |
||
133 | * \see dd_function_table::UnmapRenderbuffer |
||
134 | */ |
||
135 | static void |
||
136 | intel_unmap_renderbuffer(struct gl_context *ctx, |
||
137 | struct gl_renderbuffer *rb) |
||
138 | { |
||
139 | struct brw_context *brw = brw_context(ctx); |
||
140 | struct swrast_renderbuffer *srb = (struct swrast_renderbuffer *)rb; |
||
141 | struct intel_renderbuffer *irb = intel_renderbuffer(rb); |
||
142 | |||
143 | DBG("%s: rb %d (%s)\n", __FUNCTION__, |
||
144 | rb->Name, _mesa_get_format_name(rb->Format)); |
||
145 | |||
146 | if (srb->Buffer) { |
||
147 | /* this is a malloc'd renderbuffer (accum buffer) */ |
||
148 | /* nothing to do */ |
||
149 | return; |
||
150 | } |
||
151 | |||
152 | intel_miptree_unmap(brw, irb->mt, irb->mt_level, irb->mt_layer); |
||
153 | } |
||
154 | |||
155 | |||
156 | /** |
||
157 | * Round up the requested multisample count to the next supported sample size. |
||
158 | */ |
||
159 | unsigned |
||
160 | intel_quantize_num_samples(struct intel_screen *intel, unsigned num_samples) |
||
161 | { |
||
162 | switch (intel->gen) { |
||
163 | case 6: |
||
164 | /* Gen6 supports only 4x multisampling. */ |
||
165 | if (num_samples > 0) |
||
166 | return 4; |
||
167 | else |
||
168 | return 0; |
||
169 | case 7: |
||
170 | /* Gen7 supports 4x and 8x multisampling. */ |
||
171 | if (num_samples > 4) |
||
172 | return 8; |
||
173 | else if (num_samples > 0) |
||
174 | return 4; |
||
175 | else |
||
176 | return 0; |
||
177 | return 0; |
||
178 | default: |
||
179 | /* MSAA unsupported. */ |
||
180 | return 0; |
||
181 | } |
||
182 | } |
||
183 | |||
184 | |||
185 | /** |
||
186 | * Called via glRenderbufferStorageEXT() to set the format and allocate |
||
187 | * storage for a user-created renderbuffer. |
||
188 | */ |
||
189 | static GLboolean |
||
190 | intel_alloc_renderbuffer_storage(struct gl_context * ctx, struct gl_renderbuffer *rb, |
||
191 | GLenum internalFormat, |
||
192 | GLuint width, GLuint height) |
||
193 | { |
||
194 | struct brw_context *brw = brw_context(ctx); |
||
195 | struct intel_screen *screen = brw->intelScreen; |
||
196 | struct intel_renderbuffer *irb = intel_renderbuffer(rb); |
||
197 | rb->NumSamples = intel_quantize_num_samples(screen, rb->NumSamples); |
||
198 | |||
199 | switch (internalFormat) { |
||
200 | default: |
||
201 | /* Use the same format-choice logic as for textures. |
||
202 | * Renderbuffers aren't any different from textures for us, |
||
203 | * except they're less useful because you can't texture with |
||
204 | * them. |
||
205 | */ |
||
206 | rb->Format = ctx->Driver.ChooseTextureFormat(ctx, GL_TEXTURE_2D, |
||
207 | internalFormat, |
||
208 | GL_NONE, GL_NONE); |
||
209 | break; |
||
210 | case GL_STENCIL_INDEX: |
||
211 | case GL_STENCIL_INDEX1_EXT: |
||
212 | case GL_STENCIL_INDEX4_EXT: |
||
213 | case GL_STENCIL_INDEX8_EXT: |
||
214 | case GL_STENCIL_INDEX16_EXT: |
||
215 | /* These aren't actual texture formats, so force them here. */ |
||
216 | if (brw->has_separate_stencil) { |
||
217 | rb->Format = MESA_FORMAT_S8; |
||
218 | } else { |
||
219 | assert(!brw->must_use_separate_stencil); |
||
220 | rb->Format = MESA_FORMAT_S8_Z24; |
||
221 | } |
||
222 | break; |
||
223 | } |
||
224 | |||
225 | rb->Width = width; |
||
226 | rb->Height = height; |
||
227 | rb->_BaseFormat = _mesa_base_fbo_format(ctx, internalFormat); |
||
228 | |||
229 | intel_miptree_release(&irb->mt); |
||
230 | |||
231 | DBG("%s: %s: %s (%dx%d)\n", __FUNCTION__, |
||
232 | _mesa_lookup_enum_by_nr(internalFormat), |
||
233 | _mesa_get_format_name(rb->Format), width, height); |
||
234 | |||
235 | if (width == 0 || height == 0) |
||
236 | return true; |
||
237 | |||
238 | irb->mt = intel_miptree_create_for_renderbuffer(brw, rb->Format, |
||
239 | width, height, |
||
240 | rb->NumSamples); |
||
241 | if (!irb->mt) |
||
242 | return false; |
||
243 | |||
244 | return true; |
||
245 | } |
||
246 | |||
247 | |||
248 | static void |
||
249 | intel_image_target_renderbuffer_storage(struct gl_context *ctx, |
||
250 | struct gl_renderbuffer *rb, |
||
251 | void *image_handle) |
||
252 | { |
||
253 | struct brw_context *brw = brw_context(ctx); |
||
254 | struct intel_renderbuffer *irb; |
||
255 | __DRIscreen *screen; |
||
256 | __DRIimage *image; |
||
257 | |||
258 | screen = brw->intelScreen->driScrnPriv; |
||
259 | image = screen->dri2.image->lookupEGLImage(screen, image_handle, |
||
260 | screen->loaderPrivate); |
||
261 | if (image == NULL) |
||
262 | return; |
||
263 | |||
264 | /* __DRIimage is opaque to the core so it has to be checked here */ |
||
265 | switch (image->format) { |
||
266 | case MESA_FORMAT_RGBA8888_REV: |
||
267 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
268 | "glEGLImageTargetRenderbufferStorage(unsupported image format"); |
||
269 | return; |
||
270 | break; |
||
271 | default: |
||
272 | break; |
||
273 | } |
||
274 | |||
275 | irb = intel_renderbuffer(rb); |
||
276 | intel_miptree_release(&irb->mt); |
||
277 | irb->mt = intel_miptree_create_for_bo(brw, |
||
278 | image->region->bo, |
||
279 | image->format, |
||
280 | image->offset, |
||
281 | image->region->width, |
||
282 | image->region->height, |
||
283 | image->region->pitch, |
||
284 | image->region->tiling); |
||
285 | if (!irb->mt) |
||
286 | return; |
||
287 | |||
288 | rb->InternalFormat = image->internal_format; |
||
289 | rb->Width = image->region->width; |
||
290 | rb->Height = image->region->height; |
||
291 | rb->Format = image->format; |
||
292 | rb->_BaseFormat = _mesa_base_fbo_format(ctx, image->internal_format); |
||
293 | rb->NeedsFinishRenderTexture = true; |
||
294 | } |
||
295 | |||
296 | /** |
||
297 | * Called by _mesa_resize_framebuffer() for each hardware renderbuffer when a |
||
298 | * window system framebuffer is resized. |
||
299 | * |
||
300 | * Any actual buffer reallocations for hardware renderbuffers (which would |
||
301 | * have triggered _mesa_resize_framebuffer()) were done by |
||
302 | * intel_process_dri2_buffer(). |
||
303 | */ |
||
304 | static GLboolean |
||
305 | intel_alloc_window_storage(struct gl_context * ctx, struct gl_renderbuffer *rb, |
||
306 | GLenum internalFormat, GLuint width, GLuint height) |
||
307 | { |
||
308 | ASSERT(rb->Name == 0); |
||
309 | rb->Width = width; |
||
310 | rb->Height = height; |
||
311 | rb->InternalFormat = internalFormat; |
||
312 | |||
313 | return true; |
||
314 | } |
||
315 | |||
316 | /** Dummy function for gl_renderbuffer::AllocStorage() */ |
||
317 | static GLboolean |
||
318 | intel_nop_alloc_storage(struct gl_context * ctx, struct gl_renderbuffer *rb, |
||
319 | GLenum internalFormat, GLuint width, GLuint height) |
||
320 | { |
||
321 | _mesa_problem(ctx, "intel_op_alloc_storage should never be called."); |
||
322 | return false; |
||
323 | } |
||
324 | |||
325 | /** |
||
326 | * Create a new intel_renderbuffer which corresponds to an on-screen window, |
||
327 | * not a user-created renderbuffer. |
||
328 | * |
||
329 | * \param num_samples must be quantized. |
||
330 | */ |
||
331 | struct intel_renderbuffer * |
||
332 | intel_create_renderbuffer(gl_format format, unsigned num_samples) |
||
333 | { |
||
334 | struct intel_renderbuffer *irb; |
||
335 | struct gl_renderbuffer *rb; |
||
336 | |||
337 | GET_CURRENT_CONTEXT(ctx); |
||
338 | |||
339 | irb = CALLOC_STRUCT(intel_renderbuffer); |
||
340 | if (!irb) { |
||
341 | _mesa_error(ctx, GL_OUT_OF_MEMORY, "creating renderbuffer"); |
||
342 | return NULL; |
||
343 | } |
||
344 | |||
345 | rb = &irb->Base.Base; |
||
346 | |||
347 | _mesa_init_renderbuffer(rb, 0); |
||
348 | rb->ClassID = INTEL_RB_CLASS; |
||
349 | rb->_BaseFormat = _mesa_get_format_base_format(format); |
||
350 | rb->Format = format; |
||
351 | rb->InternalFormat = rb->_BaseFormat; |
||
352 | rb->NumSamples = num_samples; |
||
353 | |||
354 | /* intel-specific methods */ |
||
355 | rb->Delete = intel_delete_renderbuffer; |
||
356 | rb->AllocStorage = intel_alloc_window_storage; |
||
357 | |||
358 | return irb; |
||
359 | } |
||
360 | |||
361 | /** |
||
362 | * Private window-system buffers (as opposed to ones shared with the display |
||
363 | * server created with intel_create_renderbuffer()) are most similar in their |
||
364 | * handling to user-created renderbuffers, but they have a resize handler that |
||
365 | * may be called at intel_update_renderbuffers() time. |
||
366 | * |
||
367 | * \param num_samples must be quantized. |
||
368 | */ |
||
369 | struct intel_renderbuffer * |
||
370 | intel_create_private_renderbuffer(gl_format format, unsigned num_samples) |
||
371 | { |
||
372 | struct intel_renderbuffer *irb; |
||
373 | |||
374 | irb = intel_create_renderbuffer(format, num_samples); |
||
375 | irb->Base.Base.AllocStorage = intel_alloc_renderbuffer_storage; |
||
376 | |||
377 | return irb; |
||
378 | } |
||
379 | |||
380 | /** |
||
381 | * Create a new renderbuffer object. |
||
382 | * Typically called via glBindRenderbufferEXT(). |
||
383 | */ |
||
384 | static struct gl_renderbuffer * |
||
385 | intel_new_renderbuffer(struct gl_context * ctx, GLuint name) |
||
386 | { |
||
387 | struct intel_renderbuffer *irb; |
||
388 | struct gl_renderbuffer *rb; |
||
389 | |||
390 | irb = CALLOC_STRUCT(intel_renderbuffer); |
||
391 | if (!irb) { |
||
392 | _mesa_error(ctx, GL_OUT_OF_MEMORY, "creating renderbuffer"); |
||
393 | return NULL; |
||
394 | } |
||
395 | |||
396 | rb = &irb->Base.Base; |
||
397 | |||
398 | _mesa_init_renderbuffer(rb, name); |
||
399 | rb->ClassID = INTEL_RB_CLASS; |
||
400 | |||
401 | /* intel-specific methods */ |
||
402 | rb->Delete = intel_delete_renderbuffer; |
||
403 | rb->AllocStorage = intel_alloc_renderbuffer_storage; |
||
404 | /* span routines set in alloc_storage function */ |
||
405 | |||
406 | return rb; |
||
407 | } |
||
408 | |||
409 | static bool |
||
410 | intel_renderbuffer_update_wrapper(struct brw_context *brw, |
||
411 | struct intel_renderbuffer *irb, |
||
412 | struct gl_texture_image *image, |
||
413 | uint32_t layer) |
||
414 | { |
||
415 | struct gl_renderbuffer *rb = &irb->Base.Base; |
||
416 | struct intel_texture_image *intel_image = intel_texture_image(image); |
||
417 | struct intel_mipmap_tree *mt = intel_image->mt; |
||
418 | int level = image->Level; |
||
419 | |||
420 | rb->Depth = image->Depth; |
||
421 | |||
422 | rb->AllocStorage = intel_nop_alloc_storage; |
||
423 | |||
424 | intel_miptree_check_level_layer(mt, level, layer); |
||
425 | irb->mt_level = level; |
||
426 | |||
427 | switch (mt->msaa_layout) { |
||
428 | case INTEL_MSAA_LAYOUT_UMS: |
||
429 | case INTEL_MSAA_LAYOUT_CMS: |
||
430 | irb->mt_layer = layer * mt->num_samples; |
||
431 | break; |
||
432 | |||
433 | default: |
||
434 | irb->mt_layer = layer; |
||
435 | } |
||
436 | |||
437 | intel_miptree_reference(&irb->mt, mt); |
||
438 | |||
439 | intel_renderbuffer_set_draw_offset(irb); |
||
440 | |||
441 | if (mt->hiz_mt == NULL && brw_is_hiz_depth_format(brw, rb->Format)) { |
||
442 | intel_miptree_alloc_hiz(brw, mt); |
||
443 | if (!mt->hiz_mt) |
||
444 | return false; |
||
445 | } |
||
446 | |||
447 | return true; |
||
448 | } |
||
449 | |||
450 | void |
||
451 | intel_renderbuffer_set_draw_offset(struct intel_renderbuffer *irb) |
||
452 | { |
||
453 | unsigned int dst_x, dst_y; |
||
454 | |||
455 | /* compute offset of the particular 2D image within the texture region */ |
||
456 | intel_miptree_get_image_offset(irb->mt, |
||
457 | irb->mt_level, |
||
458 | irb->mt_layer, |
||
459 | &dst_x, &dst_y); |
||
460 | |||
461 | irb->draw_x = dst_x; |
||
462 | irb->draw_y = dst_y; |
||
463 | } |
||
464 | |||
465 | /** |
||
466 | * Called by glFramebufferTexture[123]DEXT() (and other places) to |
||
467 | * prepare for rendering into texture memory. This might be called |
||
468 | * many times to choose different texture levels, cube faces, etc |
||
469 | * before intel_finish_render_texture() is ever called. |
||
470 | */ |
||
471 | static void |
||
472 | intel_render_texture(struct gl_context * ctx, |
||
473 | struct gl_framebuffer *fb, |
||
474 | struct gl_renderbuffer_attachment *att) |
||
475 | { |
||
476 | struct brw_context *brw = brw_context(ctx); |
||
477 | struct gl_renderbuffer *rb = att->Renderbuffer; |
||
478 | struct intel_renderbuffer *irb = intel_renderbuffer(rb); |
||
479 | struct gl_texture_image *image = rb->TexImage; |
||
480 | struct intel_texture_image *intel_image = intel_texture_image(image); |
||
481 | struct intel_mipmap_tree *mt = intel_image->mt; |
||
482 | int layer; |
||
483 | |||
484 | (void) fb; |
||
485 | |||
486 | if (att->CubeMapFace > 0) { |
||
487 | assert(att->Zoffset == 0); |
||
488 | layer = att->CubeMapFace; |
||
489 | } else { |
||
490 | layer = att->Zoffset; |
||
491 | } |
||
492 | |||
493 | if (!intel_image->mt) { |
||
494 | /* Fallback on drawing to a texture that doesn't have a miptree |
||
495 | * (has a border, width/height 0, etc.) |
||
496 | */ |
||
497 | _swrast_render_texture(ctx, fb, att); |
||
498 | return; |
||
499 | } |
||
500 | |||
501 | intel_miptree_check_level_layer(mt, att->TextureLevel, layer); |
||
502 | |||
503 | if (!intel_renderbuffer_update_wrapper(brw, irb, image, layer)) { |
||
504 | _swrast_render_texture(ctx, fb, att); |
||
505 | return; |
||
506 | } |
||
507 | |||
508 | DBG("Begin render %s texture tex=%u w=%d h=%d d=%d refcount=%d\n", |
||
509 | _mesa_get_format_name(image->TexFormat), |
||
510 | att->Texture->Name, image->Width, image->Height, image->Depth, |
||
511 | rb->RefCount); |
||
512 | } |
||
513 | |||
514 | |||
515 | /** |
||
516 | * Called by Mesa when rendering to a texture is done. |
||
517 | */ |
||
518 | static void |
||
519 | intel_finish_render_texture(struct gl_context * ctx, struct gl_renderbuffer *rb) |
||
520 | { |
||
521 | struct brw_context *brw = brw_context(ctx); |
||
522 | |||
523 | DBG("Finish render %s texture\n", _mesa_get_format_name(rb->Format)); |
||
524 | |||
525 | /* Since we've (probably) rendered to the texture and will (likely) use |
||
526 | * it in the texture domain later on in this batchbuffer, flush the |
||
527 | * batch. Once again, we wish for a domain tracker in libdrm to cover |
||
528 | * usage inside of a batchbuffer like GEM does in the kernel. |
||
529 | */ |
||
530 | intel_batchbuffer_emit_mi_flush(brw); |
||
531 | } |
||
532 | |||
533 | #define fbo_incomplete(fb, ...) do { \ |
||
534 | static GLuint msg_id = 0; \ |
||
535 | if (unlikely(ctx->Const.ContextFlags & GL_CONTEXT_FLAG_DEBUG_BIT)) { \ |
||
536 | _mesa_gl_debug(ctx, &msg_id, \ |
||
537 | MESA_DEBUG_TYPE_OTHER, \ |
||
538 | MESA_DEBUG_SEVERITY_MEDIUM, \ |
||
539 | __VA_ARGS__); \ |
||
540 | } \ |
||
541 | DBG(__VA_ARGS__); \ |
||
542 | fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED; \ |
||
543 | } while (0) |
||
544 | |||
545 | /** |
||
546 | * Do additional "completeness" testing of a framebuffer object. |
||
547 | */ |
||
548 | static void |
||
549 | intel_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb) |
||
550 | { |
||
551 | struct brw_context *brw = brw_context(ctx); |
||
552 | struct intel_renderbuffer *depthRb = |
||
553 | intel_get_renderbuffer(fb, BUFFER_DEPTH); |
||
554 | struct intel_renderbuffer *stencilRb = |
||
555 | intel_get_renderbuffer(fb, BUFFER_STENCIL); |
||
556 | struct intel_mipmap_tree *depth_mt = NULL, *stencil_mt = NULL; |
||
557 | int i; |
||
558 | |||
559 | DBG("%s() on fb %p (%s)\n", __FUNCTION__, |
||
560 | fb, (fb == ctx->DrawBuffer ? "drawbuffer" : |
||
561 | (fb == ctx->ReadBuffer ? "readbuffer" : "other buffer"))); |
||
562 | |||
563 | if (depthRb) |
||
564 | depth_mt = depthRb->mt; |
||
565 | if (stencilRb) { |
||
566 | stencil_mt = stencilRb->mt; |
||
567 | if (stencil_mt->stencil_mt) |
||
568 | stencil_mt = stencil_mt->stencil_mt; |
||
569 | } |
||
570 | |||
571 | if (depth_mt && stencil_mt) { |
||
572 | if (depth_mt == stencil_mt) { |
||
573 | /* For true packed depth/stencil (not faked on prefers-separate-stencil |
||
574 | * hardware) we need to be sure they're the same level/layer, since |
||
575 | * we'll be emitting a single packet describing the packed setup. |
||
576 | */ |
||
577 | if (depthRb->mt_level != stencilRb->mt_level || |
||
578 | depthRb->mt_layer != stencilRb->mt_layer) { |
||
579 | fbo_incomplete(fb, |
||
580 | "FBO incomplete: depth image level/layer %d/%d != " |
||
581 | "stencil image %d/%d\n", |
||
582 | depthRb->mt_level, |
||
583 | depthRb->mt_layer, |
||
584 | stencilRb->mt_level, |
||
585 | stencilRb->mt_layer); |
||
586 | } |
||
587 | } else { |
||
588 | if (!brw->has_separate_stencil) { |
||
589 | fbo_incomplete(fb, "FBO incomplete: separate stencil " |
||
590 | "unsupported\n"); |
||
591 | } |
||
592 | if (stencil_mt->format != MESA_FORMAT_S8) { |
||
593 | fbo_incomplete(fb, "FBO incomplete: separate stencil is %s " |
||
594 | "instead of S8\n", |
||
595 | _mesa_get_format_name(stencil_mt->format)); |
||
596 | } |
||
597 | if (brw->gen < 7 && !intel_renderbuffer_has_hiz(depthRb)) { |
||
598 | /* Before Gen7, separate depth and stencil buffers can be used |
||
599 | * only if HiZ is enabled. From the Sandybridge PRM, Volume 2, |
||
600 | * Part 1, Bit 3DSTATE_DEPTH_BUFFER.SeparateStencilBufferEnable: |
||
601 | * [DevSNB]: This field must be set to the same value (enabled |
||
602 | * or disabled) as Hierarchical Depth Buffer Enable. |
||
603 | */ |
||
604 | fbo_incomplete(fb, "FBO incomplete: separate stencil " |
||
605 | "without HiZ\n"); |
||
606 | } |
||
607 | } |
||
608 | } |
||
609 | |||
610 | for (i = 0; i < Elements(fb->Attachment); i++) { |
||
611 | struct gl_renderbuffer *rb; |
||
612 | struct intel_renderbuffer *irb; |
||
613 | |||
614 | if (fb->Attachment[i].Type == GL_NONE) |
||
615 | continue; |
||
616 | |||
617 | /* A supported attachment will have a Renderbuffer set either |
||
618 | * from being a Renderbuffer or being a texture that got the |
||
619 | * intel_wrap_texture() treatment. |
||
620 | */ |
||
621 | rb = fb->Attachment[i].Renderbuffer; |
||
622 | if (rb == NULL) { |
||
623 | fbo_incomplete(fb, "FBO incomplete: attachment without " |
||
624 | "renderbuffer\n"); |
||
625 | continue; |
||
626 | } |
||
627 | |||
628 | if (fb->Attachment[i].Type == GL_TEXTURE) { |
||
629 | if (rb->TexImage->Border) { |
||
630 | fbo_incomplete(fb, "FBO incomplete: texture with border\n"); |
||
631 | continue; |
||
632 | } |
||
633 | } |
||
634 | |||
635 | irb = intel_renderbuffer(rb); |
||
636 | if (irb == NULL) { |
||
637 | fbo_incomplete(fb, "FBO incomplete: software rendering " |
||
638 | "renderbuffer\n"); |
||
639 | continue; |
||
640 | } |
||
641 | |||
642 | if (!brw_render_target_supported(brw, rb)) { |
||
643 | fbo_incomplete(fb, "FBO incomplete: Unsupported HW " |
||
644 | "texture/renderbuffer format attached: %s\n", |
||
645 | _mesa_get_format_name(intel_rb_format(irb))); |
||
646 | } |
||
647 | } |
||
648 | } |
||
649 | |||
650 | /** |
||
651 | * Try to do a glBlitFramebuffer using glCopyTexSubImage2D |
||
652 | * We can do this when the dst renderbuffer is actually a texture and |
||
653 | * there is no scaling, mirroring or scissoring. |
||
654 | * |
||
655 | * \return new buffer mask indicating the buffers left to blit using the |
||
656 | * normal path. |
||
657 | */ |
||
658 | static GLbitfield |
||
659 | intel_blit_framebuffer_with_blitter(struct gl_context *ctx, |
||
660 | GLint srcX0, GLint srcY0, |
||
661 | GLint srcX1, GLint srcY1, |
||
662 | GLint dstX0, GLint dstY0, |
||
663 | GLint dstX1, GLint dstY1, |
||
664 | GLbitfield mask, GLenum filter) |
||
665 | { |
||
666 | struct brw_context *brw = brw_context(ctx); |
||
667 | |||
668 | /* Sync up the state of window system buffers. We need to do this before |
||
669 | * we go looking for the buffers. |
||
670 | */ |
||
671 | intel_prepare_render(brw); |
||
672 | |||
673 | if (mask & GL_COLOR_BUFFER_BIT) { |
||
674 | GLint i; |
||
675 | const struct gl_framebuffer *drawFb = ctx->DrawBuffer; |
||
676 | const struct gl_framebuffer *readFb = ctx->ReadBuffer; |
||
677 | struct gl_renderbuffer *src_rb = readFb->_ColorReadBuffer; |
||
678 | struct intel_renderbuffer *src_irb = intel_renderbuffer(src_rb); |
||
679 | |||
680 | if (!src_irb) { |
||
681 | perf_debug("glBlitFramebuffer(): missing src renderbuffer. " |
||
682 | "Falling back to software rendering.\n"); |
||
683 | return mask; |
||
684 | } |
||
685 | |||
686 | /* If the source and destination are the same size with no mirroring, |
||
687 | * the rectangles are within the size of the texture and there is no |
||
688 | * scissor, then we can probably use the blit engine. |
||
689 | */ |
||
690 | if (!(srcX0 - srcX1 == dstX0 - dstX1 && |
||
691 | srcY0 - srcY1 == dstY0 - dstY1 && |
||
692 | srcX1 >= srcX0 && |
||
693 | srcY1 >= srcY0 && |
||
694 | srcX0 >= 0 && srcX1 <= readFb->Width && |
||
695 | srcY0 >= 0 && srcY1 <= readFb->Height && |
||
696 | dstX0 >= 0 && dstX1 <= drawFb->Width && |
||
697 | dstY0 >= 0 && dstY1 <= drawFb->Height && |
||
698 | !ctx->Scissor.Enabled)) { |
||
699 | perf_debug("glBlitFramebuffer(): non-1:1 blit. " |
||
700 | "Falling back to software rendering.\n"); |
||
701 | return mask; |
||
702 | } |
||
703 | |||
704 | /* Blit to all active draw buffers. We don't do any pre-checking, |
||
705 | * because we assume that copying to MRTs is rare, and failure midway |
||
706 | * through copying is even more rare. Even if it was to occur, it's |
||
707 | * safe to let meta start the copy over from scratch, because |
||
708 | * glBlitFramebuffer completely overwrites the destination pixels, and |
||
709 | * results are undefined if any destination pixels have a dependency on |
||
710 | * source pixels. |
||
711 | */ |
||
712 | for (i = 0; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) { |
||
713 | struct gl_renderbuffer *dst_rb = ctx->DrawBuffer->_ColorDrawBuffers[i]; |
||
714 | struct intel_renderbuffer *dst_irb = intel_renderbuffer(dst_rb); |
||
715 | |||
716 | if (!dst_irb) { |
||
717 | perf_debug("glBlitFramebuffer(): missing dst renderbuffer. " |
||
718 | "Falling back to software rendering.\n"); |
||
719 | return mask; |
||
720 | } |
||
721 | |||
722 | gl_format src_format = _mesa_get_srgb_format_linear(src_rb->Format); |
||
723 | gl_format dst_format = _mesa_get_srgb_format_linear(dst_rb->Format); |
||
724 | if (src_format != dst_format) { |
||
725 | perf_debug("glBlitFramebuffer(): unsupported blit from %s to %s. " |
||
726 | "Falling back to software rendering.\n", |
||
727 | _mesa_get_format_name(src_format), |
||
728 | _mesa_get_format_name(dst_format)); |
||
729 | return mask; |
||
730 | } |
||
731 | |||
732 | if (!intel_miptree_blit(brw, |
||
733 | src_irb->mt, |
||
734 | src_irb->mt_level, src_irb->mt_layer, |
||
735 | srcX0, srcY0, src_rb->Name == 0, |
||
736 | dst_irb->mt, |
||
737 | dst_irb->mt_level, dst_irb->mt_layer, |
||
738 | dstX0, dstY0, dst_rb->Name == 0, |
||
739 | dstX1 - dstX0, dstY1 - dstY0, GL_COPY)) { |
||
740 | perf_debug("glBlitFramebuffer(): unknown blit failure. " |
||
741 | "Falling back to software rendering.\n"); |
||
742 | return mask; |
||
743 | } |
||
744 | } |
||
745 | |||
746 | mask &= ~GL_COLOR_BUFFER_BIT; |
||
747 | } |
||
748 | |||
749 | return mask; |
||
750 | } |
||
751 | |||
752 | static void |
||
753 | intel_blit_framebuffer(struct gl_context *ctx, |
||
754 | GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, |
||
755 | GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, |
||
756 | GLbitfield mask, GLenum filter) |
||
757 | { |
||
758 | mask = brw_blorp_framebuffer(brw_context(ctx), |
||
759 | srcX0, srcY0, srcX1, srcY1, |
||
760 | dstX0, dstY0, dstX1, dstY1, |
||
761 | mask, filter); |
||
762 | if (mask == 0x0) |
||
763 | return; |
||
764 | |||
765 | /* Try using the BLT engine. */ |
||
766 | mask = intel_blit_framebuffer_with_blitter(ctx, |
||
767 | srcX0, srcY0, srcX1, srcY1, |
||
768 | dstX0, dstY0, dstX1, dstY1, |
||
769 | mask, filter); |
||
770 | if (mask == 0x0) |
||
771 | return; |
||
772 | |||
773 | |||
774 | _mesa_meta_BlitFramebuffer(ctx, |
||
775 | srcX0, srcY0, srcX1, srcY1, |
||
776 | dstX0, dstY0, dstX1, dstY1, |
||
777 | mask, filter); |
||
778 | } |
||
779 | |||
780 | /** |
||
781 | * This is a no-op except on multisample buffers shared with DRI2. |
||
782 | */ |
||
783 | void |
||
784 | intel_renderbuffer_set_needs_downsample(struct intel_renderbuffer *irb) |
||
785 | { |
||
786 | if (irb->mt && irb->mt->singlesample_mt) |
||
787 | irb->mt->need_downsample = true; |
||
788 | } |
||
789 | |||
790 | /** |
||
791 | * Does the renderbuffer have hiz enabled? |
||
792 | */ |
||
793 | bool |
||
794 | intel_renderbuffer_has_hiz(struct intel_renderbuffer *irb) |
||
795 | { |
||
796 | return intel_miptree_slice_has_hiz(irb->mt, irb->mt_level, irb->mt_layer); |
||
797 | } |
||
798 | |||
799 | void |
||
800 | intel_renderbuffer_set_needs_hiz_resolve(struct intel_renderbuffer *irb) |
||
801 | { |
||
802 | if (irb->mt) { |
||
803 | intel_miptree_slice_set_needs_hiz_resolve(irb->mt, |
||
804 | irb->mt_level, |
||
805 | irb->mt_layer); |
||
806 | } |
||
807 | } |
||
808 | |||
809 | void |
||
810 | intel_renderbuffer_set_needs_depth_resolve(struct intel_renderbuffer *irb) |
||
811 | { |
||
812 | if (irb->mt) { |
||
813 | intel_miptree_slice_set_needs_depth_resolve(irb->mt, |
||
814 | irb->mt_level, |
||
815 | irb->mt_layer); |
||
816 | } |
||
817 | } |
||
818 | |||
819 | bool |
||
820 | intel_renderbuffer_resolve_hiz(struct brw_context *brw, |
||
821 | struct intel_renderbuffer *irb) |
||
822 | { |
||
823 | if (irb->mt) |
||
824 | return intel_miptree_slice_resolve_hiz(brw, |
||
825 | irb->mt, |
||
826 | irb->mt_level, |
||
827 | irb->mt_layer); |
||
828 | |||
829 | return false; |
||
830 | } |
||
831 | |||
832 | bool |
||
833 | intel_renderbuffer_resolve_depth(struct brw_context *brw, |
||
834 | struct intel_renderbuffer *irb) |
||
835 | { |
||
836 | if (irb->mt) |
||
837 | return intel_miptree_slice_resolve_depth(brw, |
||
838 | irb->mt, |
||
839 | irb->mt_level, |
||
840 | irb->mt_layer); |
||
841 | |||
842 | return false; |
||
843 | } |
||
844 | |||
845 | void |
||
846 | intel_renderbuffer_move_to_temp(struct brw_context *brw, |
||
847 | struct intel_renderbuffer *irb, |
||
848 | bool invalidate) |
||
849 | { |
||
850 | struct gl_renderbuffer *rb =&irb->Base.Base; |
||
851 | struct intel_texture_image *intel_image = intel_texture_image(rb->TexImage); |
||
852 | struct intel_mipmap_tree *new_mt; |
||
853 | int width, height, depth; |
||
854 | |||
855 | intel_miptree_get_dimensions_for_image(rb->TexImage, &width, &height, &depth); |
||
856 | |||
857 | new_mt = intel_miptree_create(brw, rb->TexImage->TexObject->Target, |
||
858 | intel_image->base.Base.TexFormat, |
||
859 | intel_image->base.Base.Level, |
||
860 | intel_image->base.Base.Level, |
||
861 | width, height, depth, |
||
862 | true, |
||
863 | irb->mt->num_samples, |
||
864 | INTEL_MIPTREE_TILING_ANY); |
||
865 | |||
866 | if (brw_is_hiz_depth_format(brw, new_mt->format)) { |
||
867 | intel_miptree_alloc_hiz(brw, new_mt); |
||
868 | } |
||
869 | |||
870 | intel_miptree_copy_teximage(brw, intel_image, new_mt, invalidate); |
||
871 | |||
872 | intel_miptree_reference(&irb->mt, intel_image->mt); |
||
873 | intel_renderbuffer_set_draw_offset(irb); |
||
874 | intel_miptree_release(&new_mt); |
||
875 | } |
||
876 | |||
877 | /** |
||
878 | * Do one-time context initializations related to GL_EXT_framebuffer_object. |
||
879 | * Hook in device driver functions. |
||
880 | */ |
||
881 | void |
||
882 | intel_fbo_init(struct brw_context *brw) |
||
883 | { |
||
884 | struct dd_function_table *dd = &brw->ctx.Driver; |
||
885 | dd->NewFramebuffer = intel_new_framebuffer; |
||
886 | dd->NewRenderbuffer = intel_new_renderbuffer; |
||
887 | dd->MapRenderbuffer = intel_map_renderbuffer; |
||
888 | dd->UnmapRenderbuffer = intel_unmap_renderbuffer; |
||
889 | dd->RenderTexture = intel_render_texture; |
||
890 | dd->FinishRenderTexture = intel_finish_render_texture; |
||
891 | dd->ValidateFramebuffer = intel_validate_framebuffer; |
||
892 | dd->BlitFramebuffer = intel_blit_framebuffer; |
||
893 | dd->EGLImageTargetRenderbufferStorage = |
||
894 | intel_image_target_renderbuffer_storage; |
||
895 | }>=>=>=>=>>> |