/** * Map or unmap all the renderbuffers which we may need during * software rendering. * XXX in the future, we could probably convey extra information to * reduce the number of mappings needed. I.e. if doing a glReadPixels * from the depth buffer, we really only need one mapping. * * XXX Rewrite this function someday. * We can probably just loop over all the renderbuffer attachments, * map/unmap all of them, and not worry about the _ColorDrawBuffers * _ColorReadBuffer, _DepthBuffer or _StencilBuffer fields. */ static void intel_map_unmap_framebuffer(struct intel_context *intel, struct gl_framebuffer *fb, GLboolean map) { GLuint i; /* color draw buffers */ for (i = 0; i < fb->_NumColorDrawBuffers; i++) { if (map) intel_renderbuffer_map(intel, fb->_ColorDrawBuffers[i]); else intel_renderbuffer_unmap(intel, fb->_ColorDrawBuffers[i]); } /* color read buffer */ if (map) intel_renderbuffer_map(intel, fb->_ColorReadBuffer); else intel_renderbuffer_unmap(intel, fb->_ColorReadBuffer); /* check for render to textures */ for (i = 0; i < BUFFER_COUNT; i++) { struct gl_renderbuffer_attachment *att = fb->Attachment + i; struct gl_texture_object *tex = att->Texture; if (tex) { /* render to texture */ ASSERT(att->Renderbuffer); if (map) intel_tex_map_images(intel, intel_texture_object(tex)); else intel_tex_unmap_images(intel, intel_texture_object(tex)); } } /* depth buffer (Note wrapper!) */ if (fb->_DepthBuffer) { if (map) intel_renderbuffer_map(intel, fb->_DepthBuffer->Wrapped); else intel_renderbuffer_unmap(intel, fb->_DepthBuffer->Wrapped); } /* stencil buffer (Note wrapper!) */ if (fb->_StencilBuffer) { if (map) intel_renderbuffer_map(intel, fb->_StencilBuffer->Wrapped); else intel_renderbuffer_unmap(intel, fb->_StencilBuffer->Wrapped); } intel_check_front_buffer_rendering(intel); }
/*********************************************************************** * Emit all state: */ void brw_upload_state(struct brw_context *brw) { struct gl_context *ctx = &brw->intel.ctx; struct intel_context *intel = &brw->intel; struct brw_state_flags *state = &brw->state.dirty; int i; static int dirty_count = 0; state->mesa |= brw->intel.NewGLState; brw->intel.NewGLState = 0; if (brw->emit_state_always) { state->mesa |= ~0; state->brw |= ~0; state->cache |= ~0; } if (brw->fragment_program != ctx->FragmentProgram._Current) { brw->fragment_program = ctx->FragmentProgram._Current; brw->state.dirty.brw |= BRW_NEW_FRAGMENT_PROGRAM; } if (brw->vertex_program != ctx->VertexProgram._Current) { brw->vertex_program = ctx->VertexProgram._Current; brw->state.dirty.brw |= BRW_NEW_VERTEX_PROGRAM; } if ((state->mesa | state->cache | state->brw) == 0) return; intel_check_front_buffer_rendering(intel); if (unlikely(INTEL_DEBUG)) { /* Debug version which enforces various sanity checks on the * state flags which are generated and checked to help ensure * state atoms are ordered correctly in the list. */ struct brw_state_flags examined, prev; memset(&examined, 0, sizeof(examined)); prev = *state; for (i = 0; i < brw->num_atoms; i++) { const struct brw_tracked_state *atom = brw->atoms[i]; struct brw_state_flags generated; if (check_state(state, &atom->dirty)) { atom->emit(brw); } accumulate_state(&examined, &atom->dirty); /* generated = (prev ^ state) * if (examined & generated) * fail; */ xor_states(&generated, &prev, state); assert(!check_state(&examined, &generated)); prev = *state; } } else { for (i = 0; i < brw->num_atoms; i++) { const struct brw_tracked_state *atom = brw->atoms[i]; if (check_state(state, &atom->dirty)) { atom->emit(brw); } } } if (unlikely(INTEL_DEBUG & DEBUG_STATE)) { brw_update_dirty_count(mesa_bits, state->mesa); brw_update_dirty_count(brw_bits, state->brw); brw_update_dirty_count(cache_bits, state->cache); if (dirty_count++ % 1000 == 0) { brw_print_dirty_count(mesa_bits, state->mesa); brw_print_dirty_count(brw_bits, state->brw); brw_print_dirty_count(cache_bits, state->cache); fprintf(stderr, "\n"); } } memset(state, 0, sizeof(*state)); }
/* * Render a bitmap. */ static bool do_blit_bitmap( struct gl_context *ctx, GLint dstx, GLint dsty, GLsizei width, GLsizei height, const struct gl_pixelstore_attrib *unpack, const GLubyte *bitmap ) { struct intel_context *intel = intel_context(ctx); struct gl_framebuffer *fb = ctx->DrawBuffer; struct intel_renderbuffer *irb; GLfloat tmpColor[4]; GLubyte ubcolor[4]; GLuint color; GLsizei bitmap_width = width; GLsizei bitmap_height = height; GLint px, py; GLuint stipple[32]; GLint orig_dstx = dstx; GLint orig_dsty = dsty; /* Update draw buffer bounds */ _mesa_update_state(ctx); if (ctx->Depth.Test) { /* The blit path produces incorrect results when depth testing is on. * It seems the blit Z coord is always 1.0 (the far plane) so fragments * will likely be obscured by other, closer geometry. */ return false; } intel_prepare_render(intel); if (fb->_NumColorDrawBuffers != 1) { perf_debug("accelerated glBitmap() only supports rendering to a " "single color buffer\n"); return false; } irb = intel_renderbuffer(fb->_ColorDrawBuffers[0]); if (_mesa_is_bufferobj(unpack->BufferObj)) { bitmap = map_pbo(ctx, width, height, unpack, bitmap); if (bitmap == NULL) return true; /* even though this is an error, we're done */ } COPY_4V(tmpColor, ctx->Current.RasterColor); if (_mesa_need_secondary_color(ctx)) { ADD_3V(tmpColor, tmpColor, ctx->Current.RasterSecondaryColor); } UNCLAMPED_FLOAT_TO_UBYTE(ubcolor[0], tmpColor[0]); UNCLAMPED_FLOAT_TO_UBYTE(ubcolor[1], tmpColor[1]); UNCLAMPED_FLOAT_TO_UBYTE(ubcolor[2], tmpColor[2]); UNCLAMPED_FLOAT_TO_UBYTE(ubcolor[3], tmpColor[3]); switch (irb->mt->format) { case MESA_FORMAT_B8G8R8A8_UNORM: case MESA_FORMAT_B8G8R8X8_UNORM: color = PACK_COLOR_8888(ubcolor[3], ubcolor[0], ubcolor[1], ubcolor[2]); break; case MESA_FORMAT_B5G6R5_UNORM: color = PACK_COLOR_565(ubcolor[0], ubcolor[1], ubcolor[2]); break; default: perf_debug("Unsupported format %s in accelerated glBitmap()\n", _mesa_get_format_name(irb->mt->format)); return false; } if (!intel_check_blit_fragment_ops(ctx, tmpColor[3] == 1.0F)) return false; /* Clip to buffer bounds and scissor. */ if (!_mesa_clip_to_region(fb->_Xmin, fb->_Ymin, fb->_Xmax, fb->_Ymax, &dstx, &dsty, &width, &height)) goto out; dsty = y_flip(fb, dsty, height); #define DY 32 #define DX 32 /* Chop it all into chunks that can be digested by hardware: */ for (py = 0; py < height; py += DY) { for (px = 0; px < width; px += DX) { int h = MIN2(DY, height - py); int w = MIN2(DX, width - px); GLuint sz = ALIGN(ALIGN(w,8) * h, 64)/8; GLenum logic_op = ctx->Color.ColorLogicOpEnabled ? ctx->Color.LogicOp : GL_COPY; assert(sz <= sizeof(stipple)); memset(stipple, 0, sz); /* May need to adjust this when padding has been introduced in * sz above: * * Have to translate destination coordinates back into source * coordinates. */ int count = get_bitmap_rect(bitmap_width, bitmap_height, unpack, bitmap, -orig_dstx + (dstx + px), -orig_dsty + y_flip(fb, dsty + py, h), w, h, (GLubyte *)stipple, 8, _mesa_is_winsys_fbo(fb)); if (count == 0) continue; if (!intelEmitImmediateColorExpandBlit(intel, irb->mt->cpp, (GLubyte *)stipple, sz, color, irb->mt->region->pitch, irb->mt->region->bo, 0, irb->mt->region->tiling, dstx + px, dsty + py, w, h, logic_op)) { return false; } if (ctx->Query.CurrentOcclusionObject) ctx->Query.CurrentOcclusionObject->Result += count; } } out: if (unlikely(INTEL_DEBUG & DEBUG_SYNC)) intel_batchbuffer_flush(intel); if (_mesa_is_bufferobj(unpack->BufferObj)) { /* done with PBO so unmap it now */ ctx->Driver.UnmapBuffer(ctx, unpack->BufferObj, MAP_INTERNAL); } intel_check_front_buffer_rendering(intel); return true; }
/** * CopyPixels with the blitter. Don't support zooming, pixel transfer, etc. */ static GLboolean do_blit_copypixels(struct gl_context * ctx, GLint srcx, GLint srcy, GLsizei width, GLsizei height, GLint dstx, GLint dsty, GLenum type) { struct intel_context *intel = intel_context(ctx); struct gl_framebuffer *fb = ctx->DrawBuffer; struct gl_framebuffer *read_fb = ctx->ReadBuffer; GLint orig_dstx; GLint orig_dsty; GLint orig_srcx; GLint orig_srcy; GLboolean flip = GL_FALSE; struct intel_renderbuffer *draw_irb = NULL; struct intel_renderbuffer *read_irb = NULL; /* Update draw buffer bounds */ _mesa_update_state(ctx); switch (type) { case GL_COLOR: if (fb->_NumColorDrawBuffers != 1) { fallback_debug("glCopyPixels() fallback: MRT\n"); return GL_FALSE; } draw_irb = intel_renderbuffer(fb->_ColorDrawBuffers[0]); read_irb = intel_renderbuffer(read_fb->_ColorReadBuffer); break; case GL_DEPTH_STENCIL_EXT: draw_irb = intel_renderbuffer(fb->Attachment[BUFFER_DEPTH].Renderbuffer); read_irb = intel_renderbuffer(read_fb->Attachment[BUFFER_DEPTH].Renderbuffer); break; case GL_DEPTH: fallback_debug("glCopyPixels() fallback: GL_DEPTH\n"); return GL_FALSE; case GL_STENCIL: fallback_debug("glCopyPixels() fallback: GL_STENCIL\n"); return GL_FALSE; default: fallback_debug("glCopyPixels(): Unknown type\n"); return GL_FALSE; } if (!draw_irb) { fallback_debug("glCopyPixels() fallback: missing draw buffer\n"); return GL_FALSE; } if (!read_irb) { fallback_debug("glCopyPixels() fallback: missing read buffer\n"); return GL_FALSE; } if (draw_irb->Base.Format != read_irb->Base.Format && !(draw_irb->Base.Format == MESA_FORMAT_XRGB8888 && read_irb->Base.Format == MESA_FORMAT_ARGB8888)) { fallback_debug("glCopyPixels() fallback: mismatched formats (%s -> %s\n", _mesa_get_format_name(read_irb->Base.Format), _mesa_get_format_name(draw_irb->Base.Format)); return GL_FALSE; } /* Copypixels can be more than a straight copy. Ensure all the * extra operations are disabled: */ if (!intel_check_copypixel_blit_fragment_ops(ctx) || ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F) return GL_FALSE; intel_prepare_render(intel); intel_flush(&intel->ctx); /* Clip to destination buffer. */ orig_dstx = dstx; orig_dsty = dsty; if (!_mesa_clip_to_region(fb->_Xmin, fb->_Ymin, fb->_Xmax, fb->_Ymax, &dstx, &dsty, &width, &height)) goto out; /* Adjust src coords for our post-clipped destination origin */ srcx += dstx - orig_dstx; srcy += dsty - orig_dsty; /* Clip to source buffer. */ orig_srcx = srcx; orig_srcy = srcy; if (!_mesa_clip_to_region(0, 0, read_fb->Width, read_fb->Height, &srcx, &srcy, &width, &height)) goto out; /* Adjust dst coords for our post-clipped source origin */ dstx += srcx - orig_srcx; dsty += srcy - orig_srcy; /* Flip dest Y if it's a window system framebuffer. */ if (fb->Name == 0) { /* copypixels to a window system framebuffer */ dsty = fb->Height - dsty - height; flip = !flip; } /* Flip source Y if it's a window system framebuffer. */ if (read_fb->Name == 0) { srcy = read_fb->Height - srcy - height; flip = !flip; } srcx += read_irb->draw_x; srcy += read_irb->draw_y; dstx += draw_irb->draw_x; dsty += draw_irb->draw_y; if (!intel_region_copy(intel, draw_irb->region, 0, dstx, dsty, read_irb->region, 0, srcx, srcy, width, height, flip, ctx->Color.ColorLogicOpEnabled ? ctx->Color.LogicOp : GL_COPY)) { DBG("%s: blit failure\n", __FUNCTION__); return GL_FALSE; } out: intel_check_front_buffer_rendering(intel); DBG("%s: success\n", __FUNCTION__); return GL_TRUE; }
static bool do_blit_drawpixels(struct gl_context * ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, const struct gl_pixelstore_attrib *unpack, const GLvoid * pixels) { struct brw_context *brw = brw_context(ctx); struct intel_buffer_object *src = intel_buffer_object(unpack->BufferObj); GLuint src_offset; drm_intel_bo *src_buffer; DBG("%s\n", __FUNCTION__); if (!intel_check_blit_fragment_ops(ctx, false)) return false; if (ctx->DrawBuffer->_NumColorDrawBuffers != 1) { DBG("%s: fallback due to MRT\n", __FUNCTION__); return false; } struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[0]; struct intel_renderbuffer *irb = intel_renderbuffer(rb); if (!_mesa_format_matches_format_and_type(irb->mt->format, format, type, false)) { DBG("%s: bad format for blit\n", __FUNCTION__); return false; } if (unpack->SwapBytes || unpack->LsbFirst || unpack->SkipPixels || unpack->SkipRows) { DBG("%s: bad packing params\n", __FUNCTION__); return false; } int src_stride = _mesa_image_row_stride(unpack, width, format, type); bool src_flip = false; /* Mesa flips the src_stride for unpack->Invert, but we want our mt to have * a normal src_stride. */ if (unpack->Invert) { src_stride = -src_stride; src_flip = true; } src_offset = (GLintptr)pixels; src_offset += _mesa_image_offset(2, unpack, width, height, format, type, 0, 0, 0); intel_prepare_render(brw); src_buffer = intel_bufferobj_buffer(brw, src, src_offset, width * height * irb->mt->cpp); struct intel_mipmap_tree *pbo_mt = intel_miptree_create_for_bo(brw, src_buffer, irb->mt->format, src_offset, width, height, src_stride, I915_TILING_NONE); if (!pbo_mt) return false; if (!intel_miptree_blit(brw, pbo_mt, 0, 0, 0, 0, src_flip, irb->mt, irb->mt_level, irb->mt_layer, x, y, _mesa_is_winsys_fbo(ctx->DrawBuffer), width, height, GL_COPY)) { DBG("%s: blit failed\n", __FUNCTION__); intel_miptree_release(&pbo_mt); return false; } intel_miptree_release(&pbo_mt); if (ctx->Query.CurrentOcclusionObject) ctx->Query.CurrentOcclusionObject->Result += width * height; intel_check_front_buffer_rendering(brw); DBG("%s: success\n", __FUNCTION__); return true; }
/** * CopyPixels with the blitter. Don't support zooming, pixel transfer, etc. */ static bool do_blit_copypixels(struct gl_context * ctx, GLint srcx, GLint srcy, GLsizei width, GLsizei height, GLint dstx, GLint dsty, GLenum type) { struct intel_context *intel = intel_context(ctx); struct gl_framebuffer *fb = ctx->DrawBuffer; struct gl_framebuffer *read_fb = ctx->ReadBuffer; GLint orig_dstx; GLint orig_dsty; GLint orig_srcx; GLint orig_srcy; struct intel_renderbuffer *draw_irb = NULL; struct intel_renderbuffer *read_irb = NULL; /* Update draw buffer bounds */ _mesa_update_state(ctx); switch (type) { case GL_COLOR: if (fb->_NumColorDrawBuffers != 1) { perf_debug("glCopyPixels() fallback: MRT\n"); return false; } draw_irb = intel_renderbuffer(fb->_ColorDrawBuffers[0]); read_irb = intel_renderbuffer(read_fb->_ColorReadBuffer); break; case GL_DEPTH_STENCIL_EXT: draw_irb = intel_renderbuffer(fb->Attachment[BUFFER_DEPTH].Renderbuffer); read_irb = intel_renderbuffer(read_fb->Attachment[BUFFER_DEPTH].Renderbuffer); break; case GL_DEPTH: perf_debug("glCopyPixels() fallback: GL_DEPTH\n"); return false; case GL_STENCIL: perf_debug("glCopyPixels() fallback: GL_STENCIL\n"); return false; default: perf_debug("glCopyPixels(): Unknown type\n"); return false; } if (!draw_irb) { perf_debug("glCopyPixels() fallback: missing draw buffer\n"); return false; } if (!read_irb) { perf_debug("glCopyPixels() fallback: missing read buffer\n"); return false; } if (ctx->_ImageTransferState) { perf_debug("glCopyPixels(): Unsupported image transfer state\n"); return false; } if (ctx->Depth.Test) { perf_debug("glCopyPixels(): Unsupported depth test state\n"); return false; } if (ctx->Stencil._Enabled) { perf_debug("glCopyPixels(): Unsupported stencil test state\n"); return false; } if (ctx->Fog.Enabled || ctx->Texture._MaxEnabledTexImageUnit != -1 || ctx->FragmentProgram._Enabled) { perf_debug("glCopyPixels(): Unsupported fragment shader state\n"); return false; } if (ctx->Color.AlphaEnabled || ctx->Color.BlendEnabled) { perf_debug("glCopyPixels(): Unsupported blend state\n"); return false; } if (!ctx->Color.ColorMask[0][0] || !ctx->Color.ColorMask[0][1] || !ctx->Color.ColorMask[0][2] || !ctx->Color.ColorMask[0][3]) { perf_debug("glCopyPixels(): Unsupported color mask state\n"); return false; } if (ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F) { perf_debug("glCopyPixles(): Unsupported pixel zoom\n"); return false; } intel_prepare_render(intel); intel_flush(&intel->ctx); /* Clip to destination buffer. */ orig_dstx = dstx; orig_dsty = dsty; if (!_mesa_clip_to_region(fb->_Xmin, fb->_Ymin, fb->_Xmax, fb->_Ymax, &dstx, &dsty, &width, &height)) goto out; /* Adjust src coords for our post-clipped destination origin */ srcx += dstx - orig_dstx; srcy += dsty - orig_dsty; /* Clip to source buffer. */ orig_srcx = srcx; orig_srcy = srcy; if (!_mesa_clip_to_region(0, 0, read_fb->Width, read_fb->Height, &srcx, &srcy, &width, &height)) goto out; /* Adjust dst coords for our post-clipped source origin */ dstx += srcx - orig_srcx; dsty += srcy - orig_srcy; if (!intel_miptree_blit(intel, read_irb->mt, read_irb->mt_level, read_irb->mt_layer, srcx, srcy, _mesa_is_winsys_fbo(read_fb), draw_irb->mt, draw_irb->mt_level, draw_irb->mt_layer, dstx, dsty, _mesa_is_winsys_fbo(fb), width, height, (ctx->Color.ColorLogicOpEnabled ? ctx->Color.LogicOp : GL_COPY))) { DBG("%s: blit failure\n", __func__); return false; } if (ctx->Query.CurrentOcclusionObject) ctx->Query.CurrentOcclusionObject->Result += width * height; out: intel_check_front_buffer_rendering(intel); DBG("%s: success\n", __func__); return true; }