/** * Called via glMapBufferRange and glMapBuffer * * The goal of this extension is to allow apps to accumulate their rendering * at the same time as they accumulate their buffer object. Without it, * you'd end up blocking on execution of rendering every time you mapped * the buffer to put new data in. * * We support it in 3 ways: If unsynchronized, then don't bother * flushing the batchbuffer before mapping the buffer, which can save blocking * in many cases. If we would still block, and they allow the whole buffer * to be invalidated, then just allocate a new buffer to replace the old one. * If not, and we'd block, and they allow the subrange of the buffer to be * invalidated, then we can make a new little BO, let them write into that, * and blit it into the real BO at unmap time. */ static void * intel_bufferobj_map_range(struct gl_context * ctx, GLintptr offset, GLsizeiptr length, GLbitfield access, struct gl_buffer_object *obj) { struct intel_context *intel = intel_context(ctx); struct intel_buffer_object *intel_obj = intel_buffer_object(obj); assert(intel_obj); /* _mesa_MapBufferRange (GL entrypoint) sets these, but the vbo module also * internally uses our functions directly. */ obj->Offset = offset; obj->Length = length; obj->AccessFlags = access; if (intel_obj->sys_buffer) { const bool read_only = (access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == GL_MAP_READ_BIT; if (!read_only && intel_obj->source) release_buffer(intel_obj); if (!intel_obj->buffer || intel_obj->source) { obj->Pointer = intel_obj->sys_buffer + offset; return obj->Pointer; } free(intel_obj->sys_buffer); intel_obj->sys_buffer = NULL; } /* If the mapping is synchronized with other GL operations, flush * the batchbuffer so that GEM knows about the buffer access for later * syncing. */ if (!(access & GL_MAP_UNSYNCHRONIZED_BIT) && drm_intel_bo_references(intel->batch.bo, intel_obj->buffer)) intel_flush(ctx); if (intel_obj->buffer == NULL) { obj->Pointer = NULL; return NULL; } /* If the user doesn't care about existing buffer contents and mapping * would cause us to block, then throw out the old buffer. */ if (!(access & GL_MAP_UNSYNCHRONIZED_BIT) && (access & GL_MAP_INVALIDATE_BUFFER_BIT) && drm_intel_bo_busy(intel_obj->buffer)) { drm_intel_bo_unreference(intel_obj->buffer); intel_bufferobj_alloc_buffer(intel, intel_obj); } /* If the user is mapping a range of an active buffer object but * doesn't require the current contents of that range, make a new * BO, and we'll copy what they put in there out at unmap or * FlushRange time. */ if ((access & GL_MAP_INVALIDATE_RANGE_BIT) && drm_intel_bo_busy(intel_obj->buffer)) { if (access & GL_MAP_FLUSH_EXPLICIT_BIT) { intel_obj->range_map_buffer = malloc(length); obj->Pointer = intel_obj->range_map_buffer; } else { intel_obj->range_map_bo = drm_intel_bo_alloc(intel->bufmgr, "range map", length, 64); if (!(access & GL_MAP_READ_BIT)) { drm_intel_gem_bo_map_gtt(intel_obj->range_map_bo); intel_obj->mapped_gtt = true; } else { drm_intel_bo_map(intel_obj->range_map_bo, (access & GL_MAP_WRITE_BIT) != 0); intel_obj->mapped_gtt = false; } obj->Pointer = intel_obj->range_map_bo->virtual; } return obj->Pointer; } if (!(access & GL_MAP_READ_BIT)) { drm_intel_gem_bo_map_gtt(intel_obj->buffer); intel_obj->mapped_gtt = true; } else { drm_intel_bo_map(intel_obj->buffer, (access & GL_MAP_WRITE_BIT) != 0); intel_obj->mapped_gtt = false; } obj->Pointer = intel_obj->buffer->virtual + offset; return obj->Pointer; }
/** * Try to do a glBlitFramebuffer using glCopyTexSubImage2D * We can do this when the dst renderbuffer is actually a texture and * there is no scaling, mirroring or scissoring. * * \return new buffer mask indicating the buffers left to blit using the * normal path. */ static GLbitfield intel_blit_framebuffer_with_blitter(struct gl_context *ctx, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) { struct intel_context *intel = intel_context(ctx); if (mask & GL_COLOR_BUFFER_BIT) { GLint i; const struct gl_framebuffer *drawFb = ctx->DrawBuffer; const struct gl_framebuffer *readFb = ctx->ReadBuffer; struct gl_renderbuffer *src_rb = readFb->_ColorReadBuffer; struct intel_renderbuffer *src_irb = intel_renderbuffer(src_rb); if (!src_irb) { perf_debug("glBlitFramebuffer(): missing src renderbuffer. " "Falling back to software rendering.\n"); return mask; } /* If the source and destination are the same size with no mirroring, * the rectangles are within the size of the texture and there is no * scissor, then we can probably use the blit engine. */ if (!(srcX0 - srcX1 == dstX0 - dstX1 && srcY0 - srcY1 == dstY0 - dstY1 && srcX1 >= srcX0 && srcY1 >= srcY0 && srcX0 >= 0 && srcX1 <= readFb->Width && srcY0 >= 0 && srcY1 <= readFb->Height && dstX0 >= 0 && dstX1 <= drawFb->Width && dstY0 >= 0 && dstY1 <= drawFb->Height && !ctx->Scissor.EnableFlags)) { perf_debug("glBlitFramebuffer(): non-1:1 blit. " "Falling back to software rendering.\n"); return mask; } /* Blit to all active draw buffers. We don't do any pre-checking, * because we assume that copying to MRTs is rare, and failure midway * through copying is even more rare. Even if it was to occur, it's * safe to let meta start the copy over from scratch, because * glBlitFramebuffer completely overwrites the destination pixels, and * results are undefined if any destination pixels have a dependency on * source pixels. */ for (i = 0; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) { struct gl_renderbuffer *dst_rb = ctx->DrawBuffer->_ColorDrawBuffers[i]; struct intel_renderbuffer *dst_irb = intel_renderbuffer(dst_rb); if (!dst_irb) { perf_debug("glBlitFramebuffer(): missing dst renderbuffer. " "Falling back to software rendering.\n"); return mask; } mesa_format src_format = _mesa_get_srgb_format_linear(src_rb->Format); mesa_format dst_format = _mesa_get_srgb_format_linear(dst_rb->Format); if (src_format != dst_format) { perf_debug("glBlitFramebuffer(): unsupported blit from %s to %s. " "Falling back to software rendering.\n", _mesa_get_format_name(src_format), _mesa_get_format_name(dst_format)); return mask; } if (!intel_miptree_blit(intel, src_irb->mt, src_irb->mt_level, src_irb->mt_layer, srcX0, srcY0, src_rb->Name == 0, dst_irb->mt, dst_irb->mt_level, dst_irb->mt_layer, dstX0, dstY0, dst_rb->Name == 0, dstX1 - dstX0, dstY1 - dstY0, GL_COPY)) { perf_debug("glBlitFramebuffer(): unknown blit failure. " "Falling back to software rendering.\n"); return mask; } } mask &= ~GL_COLOR_BUFFER_BIT; } return mask; }
/** * Perform glClear where mask contains only color, depth, and/or stencil. * * The implementation is based on calling into Mesa to set GL state and * performing normal triangle rendering. The intent of this path is to * have as generic a path as possible, so that any driver could make use of * it. */ void intel_clear_tris(GLcontext *ctx, GLbitfield mask) { struct intel_context *intel = intel_context(ctx); GLfloat dst_z; struct gl_framebuffer *fb = ctx->DrawBuffer; int i; GLboolean saved_fp_enable = GL_FALSE, saved_vp_enable = GL_FALSE; GLuint saved_shader_program = 0; unsigned int saved_active_texture; struct gl_array_object *arraySave = NULL; if (!intel->clear.arrayObj) init_clear(ctx); assert((mask & ~(TRI_CLEAR_COLOR_BITS | BUFFER_BIT_DEPTH | BUFFER_BIT_STENCIL)) == 0); _mesa_PushAttrib(GL_COLOR_BUFFER_BIT | GL_CURRENT_BIT | GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT | GL_POLYGON_BIT | GL_STENCIL_BUFFER_BIT | GL_TRANSFORM_BIT | GL_CURRENT_BIT); saved_active_texture = ctx->Texture.CurrentUnit; /* Disable existing GL state we don't want to apply to a clear. */ _mesa_Disable(GL_ALPHA_TEST); _mesa_Disable(GL_BLEND); _mesa_Disable(GL_CULL_FACE); _mesa_Disable(GL_FOG); _mesa_Disable(GL_POLYGON_SMOOTH); _mesa_Disable(GL_POLYGON_STIPPLE); _mesa_Disable(GL_POLYGON_OFFSET_FILL); _mesa_Disable(GL_LIGHTING); _mesa_Disable(GL_CLIP_PLANE0); _mesa_Disable(GL_CLIP_PLANE1); _mesa_Disable(GL_CLIP_PLANE2); _mesa_Disable(GL_CLIP_PLANE3); _mesa_Disable(GL_CLIP_PLANE4); _mesa_Disable(GL_CLIP_PLANE5); _mesa_PolygonMode(GL_FRONT_AND_BACK, GL_FILL); if (ctx->Extensions.ARB_fragment_program && ctx->FragmentProgram.Enabled) { saved_fp_enable = GL_TRUE; _mesa_Disable(GL_FRAGMENT_PROGRAM_ARB); } if (ctx->Extensions.ARB_vertex_program && ctx->VertexProgram.Enabled) { saved_vp_enable = GL_TRUE; _mesa_Disable(GL_VERTEX_PROGRAM_ARB); } if (ctx->Extensions.ARB_shader_objects && ctx->Shader.CurrentProgram) { saved_shader_program = ctx->Shader.CurrentProgram->Name; _mesa_UseProgramObjectARB(0); } if (ctx->Texture._EnabledUnits != 0) { int i; for (i = 0; i < ctx->Const.MaxTextureUnits; i++) { _mesa_ActiveTextureARB(GL_TEXTURE0 + i); _mesa_Disable(GL_TEXTURE_1D); _mesa_Disable(GL_TEXTURE_2D); _mesa_Disable(GL_TEXTURE_3D); if (ctx->Extensions.ARB_texture_cube_map) _mesa_Disable(GL_TEXTURE_CUBE_MAP_ARB); if (ctx->Extensions.NV_texture_rectangle) _mesa_Disable(GL_TEXTURE_RECTANGLE_NV); if (ctx->Extensions.MESA_texture_array) { _mesa_Disable(GL_TEXTURE_1D_ARRAY_EXT); _mesa_Disable(GL_TEXTURE_2D_ARRAY_EXT); } } } /* save current array object, bind our private one */ _mesa_reference_array_object(ctx, &arraySave, ctx->Array.ArrayObj); _mesa_reference_array_object(ctx, &ctx->Array.ArrayObj, intel->clear.arrayObj); intel_meta_set_passthrough_transform(intel); for (i = 0; i < 4; i++) { COPY_4FV(intel->clear.color[i], ctx->Color.ClearColor); } /* convert clear Z from [0,1] to NDC coord in [-1,1] */ dst_z = -1.0 + 2.0 * ctx->Depth.Clear; /* Prepare the vertices, which are the same regardless of which buffer we're * drawing to. */ intel->clear.vertices[0][0] = fb->_Xmin; intel->clear.vertices[0][1] = fb->_Ymin; intel->clear.vertices[0][2] = dst_z; intel->clear.vertices[1][0] = fb->_Xmax; intel->clear.vertices[1][1] = fb->_Ymin; intel->clear.vertices[1][2] = dst_z; intel->clear.vertices[2][0] = fb->_Xmax; intel->clear.vertices[2][1] = fb->_Ymax; intel->clear.vertices[2][2] = dst_z; intel->clear.vertices[3][0] = fb->_Xmin; intel->clear.vertices[3][1] = fb->_Ymax; intel->clear.vertices[3][2] = dst_z; while (mask != 0) { GLuint this_mask = 0; GLuint color_bit; color_bit = _mesa_ffs(mask & TRI_CLEAR_COLOR_BITS); if (color_bit != 0) this_mask |= (1 << (color_bit - 1)); /* Clear depth/stencil in the same pass as color. */ this_mask |= (mask & (BUFFER_BIT_DEPTH | BUFFER_BIT_STENCIL)); /* Select the current color buffer and use the color write mask if * we have one, otherwise don't write any color channels. */ if (this_mask & BUFFER_BIT_FRONT_LEFT) _mesa_DrawBuffer(GL_FRONT_LEFT); else if (this_mask & BUFFER_BIT_BACK_LEFT) _mesa_DrawBuffer(GL_BACK_LEFT); else if (color_bit != 0) _mesa_DrawBuffer(GL_COLOR_ATTACHMENT0 + (color_bit - BUFFER_COLOR0 - 1)); else _mesa_ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); /* Control writing of the depth clear value to depth. */ if (this_mask & BUFFER_BIT_DEPTH) { _mesa_DepthFunc(GL_ALWAYS); _mesa_Enable(GL_DEPTH_TEST); } else { _mesa_Disable(GL_DEPTH_TEST); _mesa_DepthMask(GL_FALSE); } /* Control writing of the stencil clear value to stencil. */ if (this_mask & BUFFER_BIT_STENCIL) { _mesa_Enable(GL_STENCIL_TEST); _mesa_StencilOpSeparate(GL_FRONT_AND_BACK, GL_REPLACE, GL_REPLACE, GL_REPLACE); _mesa_StencilFuncSeparate(GL_FRONT_AND_BACK, GL_ALWAYS, ctx->Stencil.Clear, ctx->Stencil.WriteMask[0]); } else { _mesa_Disable(GL_STENCIL_TEST); } _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); mask &= ~this_mask; } intel_meta_restore_transform(intel); _mesa_ActiveTextureARB(GL_TEXTURE0 + saved_active_texture); if (saved_fp_enable) _mesa_Enable(GL_FRAGMENT_PROGRAM_ARB); if (saved_vp_enable) _mesa_Enable(GL_VERTEX_PROGRAM_ARB); if (saved_shader_program) _mesa_UseProgramObjectARB(saved_shader_program); _mesa_PopAttrib(); /* restore current array object */ _mesa_reference_array_object(ctx, &ctx->Array.ArrayObj, arraySave); _mesa_reference_array_object(ctx, &arraySave, NULL); }
/* Fallback to swrast for select and feedback. */ static void i830RenderMode(struct gl_context *ctx, GLenum mode) { struct intel_context *intel = intel_context(ctx); FALLBACK(intel, INTEL_FALLBACK_RENDERMODE, (mode != GL_RENDER)); }
/** * Initializes potential list of extensions if ctx == NULL, or actually enables * extensions for a context. */ void intelInitExtensions(struct gl_context *ctx) { struct intel_context *intel = intel_context(ctx); ctx->Extensions.ARB_draw_elements_base_vertex = true; ctx->Extensions.ARB_explicit_attrib_location = true; ctx->Extensions.ARB_framebuffer_object = true; ctx->Extensions.ARB_half_float_pixel = true; ctx->Extensions.ARB_internalformat_query = true; ctx->Extensions.ARB_map_buffer_range = true; ctx->Extensions.ARB_point_sprite = true; ctx->Extensions.ARB_shader_objects = true; ctx->Extensions.ARB_shading_language_100 = true; ctx->Extensions.ARB_sync = true; ctx->Extensions.ARB_texture_border_clamp = true; ctx->Extensions.ARB_texture_cube_map = true; ctx->Extensions.ARB_texture_env_combine = true; ctx->Extensions.ARB_texture_env_crossbar = true; ctx->Extensions.ARB_texture_env_dot3 = true; ctx->Extensions.ARB_texture_storage = true; ctx->Extensions.ARB_vertex_program = true; ctx->Extensions.ARB_vertex_shader = true; ctx->Extensions.EXT_blend_color = true; ctx->Extensions.EXT_blend_equation_separate = true; ctx->Extensions.EXT_blend_func_separate = true; ctx->Extensions.EXT_blend_minmax = true; ctx->Extensions.EXT_framebuffer_blit = true; ctx->Extensions.EXT_framebuffer_object = true; ctx->Extensions.EXT_fog_coord = true; ctx->Extensions.EXT_gpu_program_parameters = true; ctx->Extensions.EXT_packed_depth_stencil = true; ctx->Extensions.EXT_pixel_buffer_object = true; ctx->Extensions.EXT_point_parameters = true; ctx->Extensions.EXT_provoking_vertex = true; ctx->Extensions.EXT_secondary_color = true; ctx->Extensions.EXT_separate_shader_objects = true; ctx->Extensions.EXT_texture_env_dot3 = true; ctx->Extensions.EXT_texture_filter_anisotropic = true; ctx->Extensions.APPLE_object_purgeable = true; ctx->Extensions.MESA_pack_invert = true; ctx->Extensions.MESA_ycbcr_texture = true; ctx->Extensions.NV_blend_square = true; ctx->Extensions.NV_texture_rectangle = true; ctx->Extensions.TDFX_texture_compression_FXT1 = true; ctx->Extensions.OES_EGL_image = true; ctx->Extensions.OES_draw_texture = true; if (intel->gen >= 6) ctx->Const.GLSLVersion = 140; else ctx->Const.GLSLVersion = 120; _mesa_override_glsl_version(ctx); if (intel->gen == 6 || (intel->gen == 7 && intel->intelScreen->kernel_has_gen7_sol_reset)) ctx->Extensions.EXT_transform_feedback = true; if (intel->gen >= 6) { ctx->Extensions.EXT_framebuffer_multisample = true; ctx->Extensions.ARB_blend_func_extended = !driQueryOptionb(&intel->optionCache, "disable_blend_func_extended"); ctx->Extensions.ARB_draw_buffers_blend = true; ctx->Extensions.ARB_ES3_compatibility = true; ctx->Extensions.ARB_uniform_buffer_object = true; ctx->Extensions.ARB_texture_buffer_object = true; ctx->Extensions.ARB_texture_buffer_object_rgb32 = true; ctx->Extensions.ARB_texture_cube_map_array = true; ctx->Extensions.OES_depth_texture_cube_map = true; ctx->Extensions.ARB_shading_language_packing = true; } if (intel->gen >= 5) ctx->Extensions.EXT_timer_query = true; if (intel->gen >= 6) { uint64_t dummy; /* Test if the kernel has the ioctl. */ if (drm_intel_reg_read(intel->bufmgr, TIMESTAMP, &dummy) == 0) ctx->Extensions.ARB_timer_query = true; } if (intel->gen >= 4) { if (ctx->API == API_OPENGL_CORE) ctx->Extensions.ARB_base_instance = true; ctx->Extensions.ARB_color_buffer_float = true; ctx->Extensions.ARB_depth_buffer_float = true; ctx->Extensions.ARB_depth_clamp = true; ctx->Extensions.ARB_draw_instanced = true; ctx->Extensions.ARB_instanced_arrays = true; ctx->Extensions.ARB_fragment_coord_conventions = true; ctx->Extensions.ARB_fragment_program_shadow = true; ctx->Extensions.ARB_fragment_shader = true; ctx->Extensions.ARB_half_float_vertex = true; ctx->Extensions.ARB_occlusion_query = true; ctx->Extensions.ARB_occlusion_query2 = true; ctx->Extensions.ARB_point_sprite = true; ctx->Extensions.ARB_seamless_cube_map = true; ctx->Extensions.ARB_shader_bit_encoding = true; ctx->Extensions.ARB_shader_texture_lod = true; ctx->Extensions.ARB_texture_float = true; ctx->Extensions.EXT_texture_shared_exponent = true; ctx->Extensions.EXT_packed_float = true; ctx->Extensions.ARB_texture_compression_rgtc = true; ctx->Extensions.ARB_texture_rg = true; ctx->Extensions.ARB_texture_rgb10_a2ui = true; ctx->Extensions.ARB_vertex_type_2_10_10_10_rev = true; ctx->Extensions.EXT_draw_buffers2 = true; ctx->Extensions.EXT_framebuffer_sRGB = true; ctx->Extensions.EXT_texture_array = true; ctx->Extensions.EXT_texture_integer = true; ctx->Extensions.EXT_texture_snorm = true; ctx->Extensions.EXT_texture_sRGB = true; ctx->Extensions.EXT_texture_sRGB_decode = true; ctx->Extensions.EXT_texture_swizzle = true; ctx->Extensions.EXT_vertex_array_bgra = true; ctx->Extensions.ATI_envmap_bumpmap = true; ctx->Extensions.MESA_texture_array = true; ctx->Extensions.NV_conditional_render = true; ctx->Extensions.OES_compressed_ETC1_RGB8_texture = true; ctx->Extensions.OES_standard_derivatives = true; } if (intel->gen >= 3) { ctx->Extensions.ARB_ES2_compatibility = true; ctx->Extensions.ARB_depth_texture = true; ctx->Extensions.ARB_fragment_program = true; ctx->Extensions.ARB_shadow = true; ctx->Extensions.ARB_texture_non_power_of_two = true; ctx->Extensions.EXT_shadow_funcs = true; ctx->Extensions.EXT_stencil_two_side = true; ctx->Extensions.ATI_separate_stencil = true; ctx->Extensions.ATI_texture_env_combine3 = true; ctx->Extensions.NV_texture_env_combine4 = true; if (driQueryOptionb(&intel->optionCache, "fragment_shader")) ctx->Extensions.ARB_fragment_shader = true; if (driQueryOptionb(&intel->optionCache, "stub_occlusion_query")) ctx->Extensions.ARB_occlusion_query = true; } if (intel->ctx.Mesa_DXTn || driQueryOptionb(&intel->optionCache, "force_s3tc_enable")) ctx->Extensions.EXT_texture_compression_s3tc = true; ctx->Extensions.ANGLE_texture_compression_dxt = true; if (intel->gen >= 4) { ctx->Extensions.NV_primitive_restart = true; } }
/* May fail if out of video memory for texture or vbo upload, or on * fallback conditions. */ static GLboolean brw_try_draw_prims( GLcontext *ctx, const struct gl_client_array *arrays[], const struct _mesa_prim *prim, GLuint nr_prims, const struct _mesa_index_buffer *ib, GLuint min_index, GLuint max_index ) { struct intel_context *intel = intel_context(ctx); struct brw_context *brw = brw_context(ctx); GLboolean retval = GL_FALSE; GLboolean warn = GL_FALSE; GLboolean first_time = GL_TRUE; GLuint i; if (ctx->NewState) _mesa_update_state( ctx ); /* We have to validate the textures *before* checking for fallbacks; * otherwise, the software fallback won't be able to rely on the * texture state, the firstLevel and lastLevel fields won't be * set in the intel texture object (they'll both be 0), and the * software fallback will segfault if it attempts to access any * texture level other than level 0. */ brw_validate_textures( brw ); if (check_fallbacks(brw, prim, nr_prims)) return GL_FALSE; /* Bind all inputs, derive varying and size information: */ brw_merge_inputs( brw, arrays ); brw->ib.ib = ib; brw->state.dirty.brw |= BRW_NEW_INDICES; brw->vb.min_index = min_index; brw->vb.max_index = max_index; brw->state.dirty.brw |= BRW_NEW_VERTICES; /* Have to validate state quite late. Will rebuild tnl_program, * which depends on varying information. * * Note this is where brw->vs->prog_data.inputs_read is calculated, * so can't access it earlier. */ intel_prepare_render(intel); for (i = 0; i < nr_prims; i++) { uint32_t hw_prim; /* Flush the batch if it's approaching full, so that we don't wrap while * we've got validated state that needs to be in the same batch as the * primitives. This fraction is just a guess (minimal full state plus * a primitive is around 512 bytes), and would be better if we had * an upper bound of how much we might emit in a single * brw_try_draw_prims(). */ intel_batchbuffer_require_space(intel->batch, intel->batch->size / 4); hw_prim = brw_set_prim(brw, &prim[i]); if (first_time || (brw->state.dirty.brw & BRW_NEW_PRIMITIVE)) { first_time = GL_FALSE; brw_validate_state(brw); /* Various fallback checks: */ if (brw->intel.Fallback) goto out; /* Check that we can fit our state in with our existing batchbuffer, or * flush otherwise. */ if (dri_bufmgr_check_aperture_space(brw->state.validated_bos, brw->state.validated_bo_count)) { static GLboolean warned; intel_batchbuffer_flush(intel->batch); /* Validate the state after we flushed the batch (which would have * changed the set of dirty state). If we still fail to * check_aperture, warn of what's happening, but attempt to continue * on since it may succeed anyway, and the user would probably rather * see a failure and a warning than a fallback. */ brw_validate_state(brw); if (!warned && dri_bufmgr_check_aperture_space(brw->state.validated_bos, brw->state.validated_bo_count)) { warn = GL_TRUE; warned = GL_TRUE; } } intel->no_batch_wrap = GL_TRUE; brw_upload_state(brw); } brw_emit_prim(brw, &prim[i], hw_prim); intel->no_batch_wrap = GL_FALSE; retval = GL_TRUE; } if (intel->always_flush_batch) intel_batchbuffer_flush(intel->batch); out: brw_state_cache_check_size(brw); if (warn) fprintf(stderr, "i965: Single primitive emit potentially exceeded " "available aperture space\n"); if (!retval) DBG("%s failed\n", __FUNCTION__); return retval; }
static void brw_emit_vertices(struct brw_context *brw) { struct gl_context *ctx = &brw->intel.ctx; struct intel_context *intel = intel_context(ctx); GLuint i, nr_elements; brw_prepare_vertices(brw); brw_emit_query_begin(brw); /* If the VS doesn't read any inputs (calculating vertex position from * a state variable for some reason, for example), emit a single pad * VERTEX_ELEMENT struct and bail. * * The stale VB state stays in place, but they don't do anything unless * a VE loads from them. */ if (brw->vb.nr_enabled == 0) { BEGIN_BATCH(3); OUT_BATCH((_3DSTATE_VERTEX_ELEMENTS << 16) | 1); if (intel->gen >= 6) { OUT_BATCH((0 << GEN6_VE0_INDEX_SHIFT) | GEN6_VE0_VALID | (BRW_SURFACEFORMAT_R32G32B32A32_FLOAT << BRW_VE0_FORMAT_SHIFT) | (0 << BRW_VE0_SRC_OFFSET_SHIFT)); } else { OUT_BATCH((0 << BRW_VE0_INDEX_SHIFT) | BRW_VE0_VALID | (BRW_SURFACEFORMAT_R32G32B32A32_FLOAT << BRW_VE0_FORMAT_SHIFT) | (0 << BRW_VE0_SRC_OFFSET_SHIFT)); } OUT_BATCH((BRW_VE1_COMPONENT_STORE_0 << BRW_VE1_COMPONENT_0_SHIFT) | (BRW_VE1_COMPONENT_STORE_0 << BRW_VE1_COMPONENT_1_SHIFT) | (BRW_VE1_COMPONENT_STORE_0 << BRW_VE1_COMPONENT_2_SHIFT) | (BRW_VE1_COMPONENT_STORE_1_FLT << BRW_VE1_COMPONENT_3_SHIFT)); CACHED_BATCH(); return; } /* Now emit VB and VEP state packets. */ if (brw->vb.nr_buffers) { if (intel->gen >= 6) { assert(brw->vb.nr_buffers <= 33); } else { assert(brw->vb.nr_buffers <= 17); } BEGIN_BATCH(1 + 4*brw->vb.nr_buffers); OUT_BATCH((_3DSTATE_VERTEX_BUFFERS << 16) | (4*brw->vb.nr_buffers - 1)); for (i = 0; i < brw->vb.nr_buffers; i++) { struct brw_vertex_buffer *buffer = &brw->vb.buffers[i]; uint32_t dw0; if (intel->gen >= 6) { dw0 = buffer->step_rate ? GEN6_VB0_ACCESS_INSTANCEDATA : GEN6_VB0_ACCESS_VERTEXDATA; dw0 |= i << GEN6_VB0_INDEX_SHIFT; } else { dw0 = buffer->step_rate ? BRW_VB0_ACCESS_INSTANCEDATA : BRW_VB0_ACCESS_VERTEXDATA; dw0 |= i << BRW_VB0_INDEX_SHIFT; } if (intel->gen >= 7) dw0 |= GEN7_VB0_ADDRESS_MODIFYENABLE; OUT_BATCH(dw0 | (buffer->stride << BRW_VB0_PITCH_SHIFT)); OUT_RELOC(buffer->bo, I915_GEM_DOMAIN_VERTEX, 0, buffer->offset); if (intel->gen >= 5) { OUT_RELOC(buffer->bo, I915_GEM_DOMAIN_VERTEX, 0, buffer->bo->size - 1); } else OUT_BATCH(0); OUT_BATCH(buffer->step_rate); brw->vb.current_buffers[i].handle = buffer->bo->handle; brw->vb.current_buffers[i].offset = buffer->offset; brw->vb.current_buffers[i].stride = buffer->stride; brw->vb.current_buffers[i].step_rate = buffer->step_rate; } brw->vb.nr_current_buffers = i; ADVANCE_BATCH(); } nr_elements = brw->vb.nr_enabled + brw->vs.prog_data->uses_vertexid; /* The hardware allows one more VERTEX_ELEMENTS than VERTEX_BUFFERS, presumably * for VertexID/InstanceID. */ if (intel->gen >= 6) { assert(nr_elements <= 34); } else { assert(nr_elements <= 18); } struct brw_vertex_element *gen6_edgeflag_input = NULL; BEGIN_BATCH(1 + nr_elements * 2); OUT_BATCH((_3DSTATE_VERTEX_ELEMENTS << 16) | (2 * nr_elements - 1)); for (i = 0; i < brw->vb.nr_enabled; i++) { struct brw_vertex_element *input = brw->vb.enabled[i]; uint32_t format = get_surface_type(input->glarray->Type, input->glarray->Size, input->glarray->Format, input->glarray->Normalized, input->glarray->Integer); uint32_t comp0 = BRW_VE1_COMPONENT_STORE_SRC; uint32_t comp1 = BRW_VE1_COMPONENT_STORE_SRC; uint32_t comp2 = BRW_VE1_COMPONENT_STORE_SRC; uint32_t comp3 = BRW_VE1_COMPONENT_STORE_SRC; /* The gen4 driver expects edgeflag to come in as a float, and passes * that float on to the tests in the clipper. Mesa's current vertex * attribute value for EdgeFlag is stored as a float, which works out. * glEdgeFlagPointer, on the other hand, gives us an unnormalized * integer ubyte. Just rewrite that to convert to a float. */ if (input->attrib == VERT_ATTRIB_EDGEFLAG) { /* Gen6+ passes edgeflag as sideband along with the vertex, instead * of in the VUE. We have to upload it sideband as the last vertex * element according to the B-Spec. */ if (intel->gen >= 6) { gen6_edgeflag_input = input; continue; } if (format == BRW_SURFACEFORMAT_R8_UINT) format = BRW_SURFACEFORMAT_R8_SSCALED; } switch (input->glarray->Size) { case 0: comp0 = BRW_VE1_COMPONENT_STORE_0; case 1: comp1 = BRW_VE1_COMPONENT_STORE_0; case 2: comp2 = BRW_VE1_COMPONENT_STORE_0; case 3: comp3 = input->glarray->Integer ? BRW_VE1_COMPONENT_STORE_1_INT : BRW_VE1_COMPONENT_STORE_1_FLT; break; } if (intel->gen >= 6) { OUT_BATCH((input->buffer << GEN6_VE0_INDEX_SHIFT) | GEN6_VE0_VALID | (format << BRW_VE0_FORMAT_SHIFT) | (input->offset << BRW_VE0_SRC_OFFSET_SHIFT)); } else { OUT_BATCH((input->buffer << BRW_VE0_INDEX_SHIFT) | BRW_VE0_VALID | (format << BRW_VE0_FORMAT_SHIFT) | (input->offset << BRW_VE0_SRC_OFFSET_SHIFT)); } if (intel->gen >= 5) OUT_BATCH((comp0 << BRW_VE1_COMPONENT_0_SHIFT) | (comp1 << BRW_VE1_COMPONENT_1_SHIFT) | (comp2 << BRW_VE1_COMPONENT_2_SHIFT) | (comp3 << BRW_VE1_COMPONENT_3_SHIFT)); else OUT_BATCH((comp0 << BRW_VE1_COMPONENT_0_SHIFT) | (comp1 << BRW_VE1_COMPONENT_1_SHIFT) | (comp2 << BRW_VE1_COMPONENT_2_SHIFT) | (comp3 << BRW_VE1_COMPONENT_3_SHIFT) | ((i * 4) << BRW_VE1_DST_OFFSET_SHIFT)); } if (intel->gen >= 6 && gen6_edgeflag_input) { uint32_t format = get_surface_type(gen6_edgeflag_input->glarray->Type, gen6_edgeflag_input->glarray->Size, gen6_edgeflag_input->glarray->Format, gen6_edgeflag_input->glarray->Normalized, gen6_edgeflag_input->glarray->Integer); OUT_BATCH((gen6_edgeflag_input->buffer << GEN6_VE0_INDEX_SHIFT) | GEN6_VE0_VALID | GEN6_VE0_EDGE_FLAG_ENABLE | (format << BRW_VE0_FORMAT_SHIFT) | (gen6_edgeflag_input->offset << BRW_VE0_SRC_OFFSET_SHIFT)); OUT_BATCH((BRW_VE1_COMPONENT_STORE_SRC << BRW_VE1_COMPONENT_0_SHIFT) | (BRW_VE1_COMPONENT_STORE_0 << BRW_VE1_COMPONENT_1_SHIFT) | (BRW_VE1_COMPONENT_STORE_0 << BRW_VE1_COMPONENT_2_SHIFT) | (BRW_VE1_COMPONENT_STORE_0 << BRW_VE1_COMPONENT_3_SHIFT)); } if (brw->vs.prog_data->uses_vertexid) { uint32_t dw0 = 0, dw1 = 0; dw1 = ((BRW_VE1_COMPONENT_STORE_VID << BRW_VE1_COMPONENT_0_SHIFT) | (BRW_VE1_COMPONENT_STORE_IID << BRW_VE1_COMPONENT_1_SHIFT) | (BRW_VE1_COMPONENT_STORE_0 << BRW_VE1_COMPONENT_2_SHIFT) | (BRW_VE1_COMPONENT_STORE_0 << BRW_VE1_COMPONENT_3_SHIFT)); if (intel->gen >= 6) { dw0 |= GEN6_VE0_VALID; } else { dw0 |= BRW_VE0_VALID; dw1 |= (i * 4) << BRW_VE1_DST_OFFSET_SHIFT; } /* Note that for gl_VertexID, gl_InstanceID, and gl_PrimitiveID values, * the format is ignored and the value is always int. */ OUT_BATCH(dw0); OUT_BATCH(dw1); } CACHED_BATCH(); }
/** * 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; bool flip = false; struct intel_renderbuffer *draw_irb = NULL; struct intel_renderbuffer *read_irb = NULL; gl_format read_format, draw_format; /* 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; } read_format = intel_rb_format(read_irb); draw_format = intel_rb_format(draw_irb); if (draw_format != read_format && !(draw_format == MESA_FORMAT_XRGB8888 && read_format == MESA_FORMAT_ARGB8888)) { perf_debug("glCopyPixels() fallback: mismatched formats (%s -> %s\n", _mesa_get_format_name(read_format), _mesa_get_format_name(draw_format)); return 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 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 (_mesa_is_winsys_fbo(fb)) { /* copypixels to a window system framebuffer */ dsty = fb->Height - dsty - height; flip = !flip; } /* Flip source Y if it's a window system framebuffer. */ if (_mesa_is_winsys_fbo(read_fb)) { 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; uint32_t src_pitch = read_irb->mt->region->pitch; if (flip) src_pitch = -src_pitch; if (!intelEmitCopyBlit(intel, draw_irb->mt->cpp, src_pitch, read_irb->mt->region->bo, 0, read_irb->mt->region->tiling, draw_irb->mt->region->pitch, draw_irb->mt->region->bo, 0, draw_irb->mt->region->tiling, srcx, srcy, dstx, dsty, width, height, ctx->Color.ColorLogicOpEnabled ? ctx->Color.LogicOp : GL_COPY)) { DBG("%s: blit failure\n", __FUNCTION__); return false; } out: intel_check_front_buffer_rendering(intel); DBG("%s: success\n", __FUNCTION__); return true; }
/* XXX: Do this for TexSubImage also: */ static bool try_pbo_upload(struct gl_context *ctx, struct gl_texture_image *image, const struct gl_pixelstore_attrib *unpack, GLenum format, GLenum type, const void *pixels) { struct intel_texture_image *intelImage = intel_texture_image(image); struct intel_context *intel = intel_context(ctx); struct intel_buffer_object *pbo = intel_buffer_object(unpack->BufferObj); GLuint src_offset, src_stride; GLuint dst_x, dst_y, dst_stride; drm_intel_bo *dst_buffer, *src_buffer; if (!_mesa_is_bufferobj(unpack->BufferObj)) return false; DBG("trying pbo upload\n"); if (intel->ctx._ImageTransferState || unpack->SkipPixels || unpack->SkipRows) { DBG("%s: image transfer\n", __FUNCTION__); return false; } if (!check_pbo_format(format, type, intelImage->base.Base.TexFormat)) { DBG("%s: format mismatch (upload to %s with format 0x%x, type 0x%x)\n", __FUNCTION__, _mesa_get_format_name(intelImage->base.Base.TexFormat), format, type); return false; } ctx->Driver.AllocTextureImageBuffer(ctx, image); if (!intelImage->mt) { DBG("%s: no miptree\n", __FUNCTION__); return false; } dst_buffer = intelImage->mt->region->bo; src_buffer = intel_bufferobj_source(intel, pbo, 64, &src_offset); /* note: potential 64-bit ptr to 32-bit int cast */ src_offset += (GLuint) (unsigned long) pixels; if (unpack->RowLength > 0) src_stride = unpack->RowLength; else src_stride = image->Width; intel_miptree_get_image_offset(intelImage->mt, intelImage->base.Base.Level, intelImage->base.Base.Face, 0, &dst_x, &dst_y); dst_stride = intelImage->mt->region->pitch; if (!intelEmitCopyBlit(intel, intelImage->mt->cpp, src_stride, src_buffer, src_offset, false, dst_stride, dst_buffer, 0, intelImage->mt->region->tiling, 0, 0, dst_x, dst_y, image->Width, image->Height, GL_COPY)) { DBG("%s: blit failed\n", __FUNCTION__); return false; } DBG("%s: success\n", __FUNCTION__); return true; }
static void brw_prepare_vertices(struct brw_context *brw) { struct gl_context *ctx = &brw->intel.ctx; struct intel_context *intel = intel_context(ctx); /* CACHE_NEW_VS_PROG */ GLbitfield64 vs_inputs = brw->vs.prog_data->inputs_read; const unsigned char *ptr = NULL; GLuint interleaved = 0, total_size = 0; unsigned int min_index = brw->vb.min_index; unsigned int max_index = brw->vb.max_index; int delta, i, j; GLboolean can_merge_uploads = GL_TRUE; struct brw_vertex_element *upload[VERT_ATTRIB_MAX]; GLuint nr_uploads = 0; /* _NEW_POLYGON * * On gen6+, edge flags don't end up in the VUE (either in or out of the * VS). Instead, they're uploaded as the last vertex element, and the data * is passed sideband through the fixed function units. So, we need to * prepare the vertex buffer for it, but it's not present in inputs_read. */ if (intel->gen >= 6 && (ctx->Polygon.FrontMode != GL_FILL || ctx->Polygon.BackMode != GL_FILL)) { vs_inputs |= VERT_BIT_EDGEFLAG; } /* First build an array of pointers to ve's in vb.inputs_read */ if (0) printf("%s %d..%d\n", __FUNCTION__, min_index, max_index); /* Accumulate the list of enabled arrays. */ brw->vb.nr_enabled = 0; while (vs_inputs) { GLuint i = ffsll(vs_inputs) - 1; struct brw_vertex_element *input = &brw->vb.inputs[i]; vs_inputs &= ~BITFIELD64_BIT(i); if (input->glarray->Size && get_size(input->glarray->Type)) brw->vb.enabled[brw->vb.nr_enabled++] = input; } if (brw->vb.nr_enabled == 0) return; if (brw->vb.nr_buffers) goto prepare; for (i = j = 0; i < brw->vb.nr_enabled; i++) { struct brw_vertex_element *input = brw->vb.enabled[i]; const struct gl_client_array *glarray = input->glarray; int type_size = get_size(glarray->Type); input->element_size = type_size * glarray->Size; if (_mesa_is_bufferobj(glarray->BufferObj)) { struct intel_buffer_object *intel_buffer = intel_buffer_object(glarray->BufferObj); int k; for (k = 0; k < i; k++) { const struct gl_client_array *other = brw->vb.enabled[k]->glarray; if (glarray->BufferObj == other->BufferObj && glarray->StrideB == other->StrideB && glarray->InstanceDivisor == other->InstanceDivisor && (uintptr_t)(glarray->Ptr - other->Ptr) < glarray->StrideB) { input->buffer = brw->vb.enabled[k]->buffer; input->offset = glarray->Ptr - other->Ptr; break; } } if (k == i) { struct brw_vertex_buffer *buffer = &brw->vb.buffers[j]; /* Named buffer object: Just reference its contents directly. */ buffer->bo = intel_bufferobj_source(intel, intel_buffer, type_size, &buffer->offset); drm_intel_bo_reference(buffer->bo); buffer->offset += (uintptr_t)glarray->Ptr; buffer->stride = glarray->StrideB; buffer->step_rate = glarray->InstanceDivisor; input->buffer = j++; input->offset = 0; } /* This is a common place to reach if the user mistakenly supplies * a pointer in place of a VBO offset. If we just let it go through, * we may end up dereferencing a pointer beyond the bounds of the * GTT. We would hope that the VBO's max_index would save us, but * Mesa appears to hand us min/max values not clipped to the * array object's _MaxElement, and _MaxElement frequently appears * to be wrong anyway. * * The VBO spec allows application termination in this case, and it's * probably a service to the poor programmer to do so rather than * trying to just not render. */ assert(input->offset < brw->vb.buffers[input->buffer].bo->size); } else { /* Queue the buffer object up to be uploaded in the next pass, * when we've decided if we're doing interleaved or not. */ if (nr_uploads == 0) { interleaved = glarray->StrideB; ptr = glarray->Ptr; } else if (interleaved != glarray->StrideB || (uintptr_t)(glarray->Ptr - ptr) > interleaved) { interleaved = 0; } else if ((uintptr_t)(glarray->Ptr - ptr) & (type_size -1)) { /* enforce natural alignment (for doubles) */ interleaved = 0; } upload[nr_uploads++] = input; total_size = ALIGN(total_size, type_size); total_size += input->element_size; if (glarray->InstanceDivisor != 0) { can_merge_uploads = GL_FALSE; } } } /* If we need to upload all the arrays, then we can trim those arrays to * only the used elements [min_index, max_index] so long as we adjust all * the values used in the 3DPRIMITIVE i.e. by setting the vertex bias. */ brw->vb.start_vertex_bias = 0; delta = min_index; if (nr_uploads == brw->vb.nr_enabled) { brw->vb.start_vertex_bias = -delta; delta = 0; } if (delta && !brw->intel.intelScreen->relaxed_relocations) min_index = delta = 0; /* Handle any arrays to be uploaded. */ if (nr_uploads > 1) { if (interleaved && interleaved <= 2*total_size) { struct brw_vertex_buffer *buffer = &brw->vb.buffers[j]; /* All uploads are interleaved, so upload the arrays together as * interleaved. First, upload the contents and set up upload[0]. */ copy_array_to_vbo_array(brw, upload[0], min_index, max_index, buffer, interleaved); buffer->offset -= delta * interleaved; for (i = 0; i < nr_uploads; i++) { /* Then, just point upload[i] at upload[0]'s buffer. */ upload[i]->offset = ((const unsigned char *)upload[i]->glarray->Ptr - ptr); upload[i]->buffer = j; } j++; nr_uploads = 0; } else if ((total_size < 2048) && can_merge_uploads) { /* Upload non-interleaved arrays into a single interleaved array */ struct brw_vertex_buffer *buffer; int count = MAX2(max_index - min_index + 1, 1); int offset; char *map; map = intel_upload_map(&brw->intel, total_size * count, total_size); for (i = offset = 0; i < nr_uploads; i++) { const unsigned char *src = upload[i]->glarray->Ptr; int size = upload[i]->element_size; int stride = upload[i]->glarray->StrideB; char *dst; int n; offset = ALIGN(offset, get_size(upload[i]->glarray->Type)); dst = map + offset; src += min_index * stride; for (n = 0; n < count; n++) { memcpy(dst, src, size); src += stride; dst += total_size; } upload[i]->offset = offset; upload[i]->buffer = j; offset += size; } assert(offset == total_size); buffer = &brw->vb.buffers[j++]; intel_upload_unmap(&brw->intel, map, offset * count, offset, &buffer->bo, &buffer->offset); buffer->stride = offset; buffer->step_rate = 0; buffer->offset -= delta * offset; nr_uploads = 0; } } /* Upload non-interleaved arrays */ for (i = 0; i < nr_uploads; i++) { struct brw_vertex_buffer *buffer = &brw->vb.buffers[j]; if (upload[i]->glarray->InstanceDivisor == 0) { copy_array_to_vbo_array(brw, upload[i], min_index, max_index, buffer, upload[i]->element_size); } else { /* This is an instanced attribute, since its InstanceDivisor * is not zero. Therefore, its data will be stepped after the * instanced draw has been run InstanceDivisor times. */ uint32_t instanced_attr_max_index = (brw->num_instances - 1) / upload[i]->glarray->InstanceDivisor; copy_array_to_vbo_array(brw, upload[i], 0, instanced_attr_max_index, buffer, upload[i]->element_size); } buffer->offset -= delta * buffer->stride; buffer->step_rate = upload[i]->glarray->InstanceDivisor; upload[i]->buffer = j++; upload[i]->offset = 0; } /* can we simply extend the current vb? */ if (j == brw->vb.nr_current_buffers) { int delta = 0; for (i = 0; i < j; i++) { int d; if (brw->vb.current_buffers[i].handle != brw->vb.buffers[i].bo->handle || brw->vb.current_buffers[i].stride != brw->vb.buffers[i].stride || brw->vb.current_buffers[i].step_rate != brw->vb.buffers[i].step_rate) break; d = brw->vb.buffers[i].offset - brw->vb.current_buffers[i].offset; if (d < 0) break; if (i == 0) delta = d / brw->vb.current_buffers[i].stride; if (delta * brw->vb.current_buffers[i].stride != d) break; } if (i == j) { brw->vb.start_vertex_bias += delta; while (--j >= 0) drm_intel_bo_unreference(brw->vb.buffers[j].bo); j = 0; } } brw->vb.nr_buffers = j; prepare: brw_prepare_query_begin(brw); }
/* May fail if out of video memory for texture or vbo upload, or on * fallback conditions. */ static bool brw_try_draw_prims( struct gl_context *ctx, const struct gl_client_array *arrays[], const struct _mesa_prim *prim, GLuint nr_prims, const struct _mesa_index_buffer *ib, GLuint min_index, GLuint max_index ) { struct intel_context *intel = intel_context(ctx); struct brw_context *brw = brw_context(ctx); bool retval = true; GLuint i; bool fail_next = false; if (ctx->NewState) _mesa_update_state( ctx ); /* We have to validate the textures *before* checking for fallbacks; * otherwise, the software fallback won't be able to rely on the * texture state, the firstLevel and lastLevel fields won't be * set in the intel texture object (they'll both be 0), and the * software fallback will segfault if it attempts to access any * texture level other than level 0. */ brw_validate_textures( brw ); /* Resolves must occur after updating state and finalizing textures but * before setting up any hardware state for this draw call. */ brw_predraw_resolve_buffers(brw); /* Bind all inputs, derive varying and size information: */ brw_merge_inputs( brw, arrays ); brw->ib.ib = ib; brw->state.dirty.brw |= BRW_NEW_INDICES; brw->vb.min_index = min_index; brw->vb.max_index = max_index; brw->state.dirty.brw |= BRW_NEW_VERTICES; /* Have to validate state quite late. Will rebuild tnl_program, * which depends on varying information. * * Note this is where brw->vs->prog_data.inputs_read is calculated, * so can't access it earlier. */ intel_prepare_render(intel); for (i = 0; i < nr_prims; i++) { int estimated_max_prim_size; estimated_max_prim_size = 512; /* batchbuffer commands */ estimated_max_prim_size += (BRW_MAX_TEX_UNIT * (sizeof(struct brw_sampler_state) + sizeof(struct gen5_sampler_default_color))); estimated_max_prim_size += 1024; /* gen6 VS push constants */ estimated_max_prim_size += 1024; /* gen6 WM push constants */ estimated_max_prim_size += 512; /* misc. pad */ /* Flush the batch if it's approaching full, so that we don't wrap while * we've got validated state that needs to be in the same batch as the * primitives. */ intel_batchbuffer_require_space(intel, estimated_max_prim_size, false); intel_batchbuffer_save_state(intel); if (intel->gen < 6) brw_set_prim(brw, &prim[i]); else gen6_set_prim(brw, &prim[i]); retry: /* Note that before the loop, brw->state.dirty.brw was set to != 0, and * that the state updated in the loop outside of this block is that in * *_set_prim or intel_batchbuffer_flush(), which only impacts * brw->state.dirty.brw. */ if (brw->state.dirty.brw) { intel->no_batch_wrap = true; brw_upload_state(brw); if (unlikely(brw->intel.Fallback)) { intel->no_batch_wrap = false; retval = false; goto out; } } if (intel->gen >= 7) gen7_emit_prim(brw, &prim[i], brw->primitive); else brw_emit_prim(brw, &prim[i], brw->primitive); intel->no_batch_wrap = false; if (dri_bufmgr_check_aperture_space(&intel->batch.bo, 1)) { if (!fail_next) { intel_batchbuffer_reset_to_saved(intel); intel_batchbuffer_flush(intel); fail_next = true; goto retry; } else { if (intel_batchbuffer_flush(intel) == -ENOSPC) { static bool warned = false; if (!warned) { fprintf(stderr, "i965: Single primitive emit exceeded" "available aperture space\n"); warned = true; } retval = false; } } } if (!_mesa_meta_in_progress(ctx)) brw_update_primitive_count(brw, &prim[i]); } if (intel->always_flush_batch) intel_batchbuffer_flush(intel); out: brw_state_cache_check_size(brw); brw_postdraw_set_buffers_need_resolve(brw); return retval; }
static GLboolean do_texture_drawpixels(GLcontext * ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, const struct gl_pixelstore_attrib *unpack, const GLvoid * pixels) { struct intel_context *intel = intel_context(ctx); struct intel_region *dst = intel_drawbuf_region(intel); struct intel_buffer_object *src = intel_buffer_object(unpack->BufferObj); GLuint rowLength = unpack->RowLength ? unpack->RowLength : width; GLuint src_offset; if (INTEL_DEBUG & DEBUG_PIXEL) fprintf(stderr, "%s\n", __FUNCTION__); intelFlush(&intel->ctx); intel->vtbl.render_start(intel); intel->vtbl.emit_state(intel); if (!dst) return GL_FALSE; if (src) { if (!_mesa_validate_pbo_access(2, unpack, width, height, 1, format, type, pixels)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawPixels"); return GL_TRUE; } } else { /* PBO only for now: */ /* _mesa_printf("%s - not PBO\n", __FUNCTION__); */ return GL_FALSE; } /* There are a couple of things we can't do yet, one of which is * set the correct state for pixel operations when GL texturing is * enabled. That's a pretty rare state and probably not worth the * effort. A completely device-independent version of this may do * more. * * Similarly, we make no attempt to merge metaops processing with * an enabled fragment program, though it would certainly be * possible. */ if (!intel_check_meta_tex_fragment_ops(ctx)) { if (INTEL_DEBUG & DEBUG_PIXEL) _mesa_printf("%s - bad GL fragment state for metaops texture\n", __FUNCTION__); return GL_FALSE; } intel->vtbl.install_meta_state(intel); /* Is this true? Also will need to turn depth testing on according * to state: */ intel->vtbl.meta_no_stencil_write(intel); intel->vtbl.meta_no_depth_write(intel); /* Set the 3d engine to draw into the destination region: */ intel->vtbl.meta_draw_region(intel, dst, intel->intelScreen->depth_region); intel->vtbl.meta_import_pixel_state(intel); src_offset = (GLuint) _mesa_image_address(2, unpack, pixels, width, height, format, type, 0, 0, 0); /* Setup the pbo up as a rectangular texture, if possible. * * TODO: This is almost always possible if the i915 fragment * program is adjusted to correctly swizzle the sampled colors. * The major exception is any 24bit texture, like RGB888, for which * there is no hardware support. */ if (!intel->vtbl.meta_tex_rect_source(intel, src->buffer, src_offset, rowLength, height, format, type)) { intel->vtbl.leave_meta_state(intel); return GL_FALSE; } intel->vtbl.meta_texture_blend_replace(intel); LOCK_HARDWARE(intel); if (intel->driDrawable->numClipRects) { __DRIdrawablePrivate *dPriv = intel->driDrawable; GLint srcx, srcy; GLint dstx, dsty; dstx = x; dsty = dPriv->h - (y + height); srcx = 0; /* skiprows/pixels already done */ srcy = 0; if (0) { const GLint orig_x = dstx; const GLint orig_y = dsty; if (!_mesa_clip_to_region(0, 0, dst->pitch, dst->height, &dstx, &dsty, &width, &height)) goto out; srcx += dstx - orig_x; srcy += dsty - orig_y; } if (INTEL_DEBUG & DEBUG_PIXEL) _mesa_printf("draw %d,%d %dx%d\n", dstx, dsty, width, height); /* Must use the regular cliprect mechanism in order to get the * drawing origin set correctly. Otherwise scissor state is in * incorrect coordinate space. Does this even need to hold the * lock??? */ intel_meta_draw_quad(intel, dstx, dstx + width * ctx->Pixel.ZoomX, dPriv->h - (y + height * ctx->Pixel.ZoomY), dPriv->h - (y), -ctx->Current.RasterPos[2] * .5, 0x00ff00ff, srcx, srcx + width, srcy + height, srcy); out: intel->vtbl.leave_meta_state(intel); intel_batchbuffer_flush(intel->batch); } UNLOCK_HARDWARE(intel); return GL_TRUE; }
/* Pros: * - no waiting for idle before updating framebuffer. * * Cons: * - if upload is by memcpy, this may actually be slower than fallback path. * - uploads the whole image even if destination is clipped * * Need to benchmark. * * Given the questions about performance, implement for pbo's only. * This path is definitely a win if the pbo is already in agp. If it * turns out otherwise, we can add the code necessary to upload client * data to agp space before performing the blit. (Though it may turn * out to be better/simpler just to use the texture engine). */ static GLboolean do_blit_drawpixels(GLcontext * ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, const struct gl_pixelstore_attrib *unpack, const GLvoid * pixels) { struct intel_context *intel = intel_context(ctx); struct intel_region *dest = intel_drawbuf_region(intel); struct intel_buffer_object *src = intel_buffer_object(unpack->BufferObj); GLuint src_offset; GLuint rowLength; struct _DriFenceObject *fence = NULL; if (INTEL_DEBUG & DEBUG_PIXEL) _mesa_printf("%s\n", __FUNCTION__); if (!dest) { if (INTEL_DEBUG & DEBUG_PIXEL) _mesa_printf("%s - no dest\n", __FUNCTION__); return GL_FALSE; } if (src) { /* This validation should be done by core mesa: */ if (!_mesa_validate_pbo_access(2, unpack, width, height, 1, format, type, pixels)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawPixels"); return GL_TRUE; } } else { /* PBO only for now: */ if (INTEL_DEBUG & DEBUG_PIXEL) _mesa_printf("%s - not PBO\n", __FUNCTION__); return GL_FALSE; } if (!intel_check_blit_format(dest, format, type)) { if (INTEL_DEBUG & DEBUG_PIXEL) _mesa_printf("%s - bad format for blit\n", __FUNCTION__); return GL_FALSE; } if (!intel_check_blit_fragment_ops(ctx)) { if (INTEL_DEBUG & DEBUG_PIXEL) _mesa_printf("%s - bad GL fragment state for blitter\n", __FUNCTION__); return GL_FALSE; } if (ctx->Pixel.ZoomX != 1.0F) { if (INTEL_DEBUG & DEBUG_PIXEL) _mesa_printf("%s - bad PixelZoomX for blit\n", __FUNCTION__); return GL_FALSE; } if (unpack->RowLength > 0) rowLength = unpack->RowLength; else rowLength = width; if (ctx->Pixel.ZoomY == -1.0F) { if (INTEL_DEBUG & DEBUG_PIXEL) _mesa_printf("%s - bad PixelZoomY for blit\n", __FUNCTION__); return GL_FALSE; /* later */ y -= height; } else if (ctx->Pixel.ZoomY == 1.0F) { rowLength = -rowLength; } else { if (INTEL_DEBUG & DEBUG_PIXEL) _mesa_printf("%s - bad PixelZoomY for blit\n", __FUNCTION__); return GL_FALSE; } src_offset = (GLuint) _mesa_image_address(2, unpack, pixels, width, height, format, type, 0, 0, 0); intelFlush(&intel->ctx); LOCK_HARDWARE(intel); if (intel->driDrawable->numClipRects) { __DRIdrawablePrivate *dPriv = intel->driDrawable; int nbox = dPriv->numClipRects; drm_clip_rect_t *box = dPriv->pClipRects; drm_clip_rect_t rect; drm_clip_rect_t dest_rect; struct _DriBufferObject *src_buffer = intel_bufferobj_buffer(intel, src, INTEL_READ); int i; dest_rect.x1 = dPriv->x + x; dest_rect.y1 = dPriv->y + dPriv->h - (y + height); dest_rect.x2 = dest_rect.x1 + width; dest_rect.y2 = dest_rect.y1 + height; for (i = 0; i < nbox; i++) { if (!intel_intersect_cliprects(&rect, &dest_rect, &box[i])) continue; intelEmitCopyBlit(intel, dest->cpp, rowLength, src_buffer, src_offset, dest->pitch, dest->buffer, 0, rect.x1 - dest_rect.x1, rect.y2 - dest_rect.y2, rect.x1, rect.y1, rect.x2 - rect.x1, rect.y2 - rect.y1, ctx->Color.ColorLogicOpEnabled ? ctx->Color.LogicOp : GL_COPY); } fence = intel_batchbuffer_flush(intel->batch); driFenceReference(fence); } UNLOCK_HARDWARE(intel); if (fence) { driFenceFinish(fence, DRM_FENCE_TYPE_EXE | DRM_I915_FENCE_TYPE_RW, GL_FALSE); driFenceUnReference(fence); } if (INTEL_DEBUG & DEBUG_PIXEL) _mesa_printf("%s - DONE\n", __FUNCTION__); return GL_TRUE; }
void intelChooseRenderState(GLcontext * ctx) { TNLcontext *tnl = TNL_CONTEXT(ctx); struct intel_context *intel = intel_context(ctx); GLuint flags = ctx->_TriangleCaps; const struct gl_fragment_program *fprog = ctx->FragmentProgram._Current; GLboolean have_wpos = (fprog && (fprog->Base.InputsRead & FRAG_BIT_WPOS)); GLuint index = 0; if (INTEL_DEBUG & DEBUG_STATE) fprintf(stderr, "\n%s\n", __FUNCTION__); if ((flags & (ANY_FALLBACK_FLAGS | ANY_RASTER_FLAGS)) || have_wpos) { if (flags & ANY_RASTER_FLAGS) { if (flags & DD_TRI_LIGHT_TWOSIDE) index |= INTEL_TWOSIDE_BIT; if (flags & DD_TRI_OFFSET) index |= INTEL_OFFSET_BIT; if (flags & DD_TRI_UNFILLED) index |= INTEL_UNFILLED_BIT; } if (have_wpos) { intel->draw_point = intel_wpos_point; intel->draw_line = intel_wpos_line; intel->draw_tri = intel_wpos_triangle; /* Make sure these get called: */ index |= INTEL_FALLBACK_BIT; } else { intel->draw_point = intel_draw_point; intel->draw_line = intel_draw_line; intel->draw_tri = intel_draw_triangle; } /* Hook in fallbacks for specific primitives. */ if (flags & ANY_FALLBACK_FLAGS) { if (flags & DD_LINE_STIPPLE) intel->draw_line = intel_fallback_line; if ((flags & DD_TRI_STIPPLE) && !intel->hw_stipple) intel->draw_tri = intel_fallback_tri; if (flags & DD_TRI_SMOOTH) { if (intel->strict_conformance) intel->draw_tri = intel_fallback_tri; } if (flags & DD_POINT_ATTEN) { if (0) intel->draw_point = intel_atten_point; else intel->draw_point = intel_fallback_point; } if (flags & DD_POINT_SMOOTH) { if (intel->strict_conformance) intel->draw_point = intel_fallback_point; } index |= INTEL_FALLBACK_BIT; } } if (intel->RenderIndex != index) { intel->RenderIndex = index; tnl->Driver.Render.Points = rast_tab[index].points; tnl->Driver.Render.Line = rast_tab[index].line; tnl->Driver.Render.Triangle = rast_tab[index].triangle; tnl->Driver.Render.Quad = rast_tab[index].quad; if (index == 0) { tnl->Driver.Render.PrimTabVerts = intel_render_tab_verts; tnl->Driver.Render.PrimTabElts = intel_render_tab_elts; tnl->Driver.Render.ClippedLine = line; /* from tritmp.h */ tnl->Driver.Render.ClippedPolygon = intelFastRenderClippedPoly; } else { tnl->Driver.Render.PrimTabVerts = _tnl_render_tab_verts; tnl->Driver.Render.PrimTabElts = _tnl_render_tab_elts; tnl->Driver.Render.ClippedLine = intelRenderClippedLine; tnl->Driver.Render.ClippedPolygon = intelRenderClippedPoly; } } }
/** * Use blitting to clear the renderbuffers named by 'flags'. * Note: we can't use the ctx->DrawBuffer->_ColorDrawBufferIndexes field * since that might include software renderbuffers or renderbuffers * which we're clearing with triangles. * \param mask bitmask of BUFFER_BIT_* values indicating buffers to clear */ GLbitfield intelClearWithBlit(struct gl_context *ctx, GLbitfield mask) { struct intel_context *intel = intel_context(ctx); struct gl_framebuffer *fb = ctx->DrawBuffer; GLuint clear_depth_value, clear_depth_mask; GLboolean all; GLint cx, cy, cw, ch; GLbitfield fail_mask = 0; BATCH_LOCALS; /* * Compute values for clearing the buffers. */ clear_depth_value = 0; clear_depth_mask = 0; if (mask & BUFFER_BIT_DEPTH) { clear_depth_value = (GLuint) (fb->_DepthMax * ctx->Depth.Clear); clear_depth_mask = XY_BLT_WRITE_RGB; } if (mask & BUFFER_BIT_STENCIL) { clear_depth_value |= (ctx->Stencil.Clear & 0xff) << 24; clear_depth_mask |= XY_BLT_WRITE_ALPHA; } cx = fb->_Xmin; if (fb->Name == 0) cy = ctx->DrawBuffer->Height - fb->_Ymax; else cy = fb->_Ymin; cw = fb->_Xmax - fb->_Xmin; ch = fb->_Ymax - fb->_Ymin; if (cw == 0 || ch == 0) return 0; all = (cw == fb->Width && ch == fb->Height); /* Loop over all renderbuffers */ mask &= (1 << BUFFER_COUNT) - 1; while (mask) { GLuint buf = _mesa_ffs(mask) - 1; GLboolean is_depth_stencil = buf == BUFFER_DEPTH || buf == BUFFER_STENCIL; struct intel_renderbuffer *irb; drm_intel_bo *write_buffer; int x1, y1, x2, y2; uint32_t clear_val; uint32_t BR13, CMD; int pitch, cpp; drm_intel_bo *aper_array[2]; mask &= ~(1 << buf); irb = intel_get_renderbuffer(fb, buf); if (irb == NULL || irb->region == NULL || irb->region->buffer == NULL) { fail_mask |= 1 << buf; continue; } /* OK, clear this renderbuffer */ write_buffer = intel_region_buffer(intel, irb->region, all ? INTEL_WRITE_FULL : INTEL_WRITE_PART); x1 = cx + irb->draw_x; y1 = cy + irb->draw_y; x2 = cx + cw + irb->draw_x; y2 = cy + ch + irb->draw_y; pitch = irb->region->pitch; cpp = irb->region->cpp; DBG("%s dst:buf(%p)/%d %d,%d sz:%dx%d\n", __FUNCTION__, irb->region->buffer, (pitch * cpp), x1, y1, x2 - x1, y2 - y1); BR13 = 0xf0 << 16; CMD = XY_COLOR_BLT_CMD; /* Setup the blit command */ if (cpp == 4) { if (is_depth_stencil) { CMD |= clear_depth_mask; } else { /* clearing RGBA */ CMD |= XY_BLT_WRITE_ALPHA | XY_BLT_WRITE_RGB; } } assert(irb->region->tiling != I915_TILING_Y); #ifndef I915 if (irb->region->tiling != I915_TILING_NONE) { CMD |= XY_DST_TILED; pitch /= 4; } #endif BR13 |= (pitch * cpp); if (is_depth_stencil) { clear_val = clear_depth_value; } else { uint8_t clear[4]; GLclampf *color = ctx->Color.ClearColor; CLAMPED_FLOAT_TO_UBYTE(clear[0], color[0]); CLAMPED_FLOAT_TO_UBYTE(clear[1], color[1]); CLAMPED_FLOAT_TO_UBYTE(clear[2], color[2]); CLAMPED_FLOAT_TO_UBYTE(clear[3], color[3]); switch (irb->Base.Format) { case MESA_FORMAT_ARGB8888: case MESA_FORMAT_XRGB8888: clear_val = PACK_COLOR_8888(clear[3], clear[0], clear[1], clear[2]); break; case MESA_FORMAT_RGB565: clear_val = PACK_COLOR_565(clear[0], clear[1], clear[2]); break; case MESA_FORMAT_ARGB4444: clear_val = PACK_COLOR_4444(clear[3], clear[0], clear[1], clear[2]); break; case MESA_FORMAT_ARGB1555: clear_val = PACK_COLOR_1555(clear[3], clear[0], clear[1], clear[2]); break; case MESA_FORMAT_A8: clear_val = PACK_COLOR_8888(clear[3], clear[3], clear[3], clear[3]); break; default: fail_mask |= 1 << buf; continue; } } BR13 |= br13_for_cpp(cpp); assert(x1 < x2); assert(y1 < y2); /* do space check before going any further */ aper_array[0] = intel->batch.bo; aper_array[1] = write_buffer; if (drm_intel_bufmgr_check_aperture_space(aper_array, ARRAY_SIZE(aper_array)) != 0) { intel_batchbuffer_flush(intel); } BEGIN_BATCH_BLT(6); OUT_BATCH(CMD); OUT_BATCH(BR13); OUT_BATCH((y1 << 16) | x1); OUT_BATCH((y2 << 16) | x2); OUT_RELOC_FENCED(write_buffer, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); OUT_BATCH(clear_val); ADVANCE_BATCH(); if (intel->always_flush_cache) intel_batchbuffer_emit_mi_flush(intel); if (buf == BUFFER_DEPTH || buf == BUFFER_STENCIL) mask &= ~(BUFFER_BIT_DEPTH | BUFFER_BIT_STENCIL); } return fail_mask; }
void intelClearWithBlit(GLcontext *ctx, GLbitfield flags) { struct intel_context *intel = intel_context( ctx ); intelScreenPrivate *intelScreen = intel->intelScreen; GLuint clear_depth, clear_color; GLint cx, cy, cw, ch; GLint cpp = intelScreen->cpp; GLboolean all; GLint i; struct intel_region *front = intel->front_region; struct intel_region *back = intel->back_region; struct intel_region *depth = intel->depth_region; GLuint BR13, FRONT_CMD, BACK_CMD, DEPTH_CMD; GLuint front_pitch; GLuint back_pitch; GLuint depth_pitch; BATCH_LOCALS; clear_color = intel->ClearColor; clear_depth = 0; if (flags & BUFFER_BIT_DEPTH) { clear_depth = (GLuint)(ctx->Depth.Clear * intel->ClearDepth); } if (flags & BUFFER_BIT_STENCIL) { clear_depth |= (ctx->Stencil.Clear & 0xff) << 24; } switch(cpp) { case 2: BR13 = (0xF0 << 16) | (1<<24); BACK_CMD = FRONT_CMD = XY_COLOR_BLT_CMD; DEPTH_CMD = XY_COLOR_BLT_CMD; break; case 4: BR13 = (0xF0 << 16) | (1<<24) | (1<<25); BACK_CMD = FRONT_CMD = (XY_COLOR_BLT_CMD | XY_COLOR_BLT_WRITE_ALPHA | XY_COLOR_BLT_WRITE_RGB); DEPTH_CMD = XY_COLOR_BLT_CMD; if (flags & BUFFER_BIT_DEPTH) DEPTH_CMD |= XY_COLOR_BLT_WRITE_RGB; if (flags & BUFFER_BIT_STENCIL) DEPTH_CMD |= XY_COLOR_BLT_WRITE_ALPHA; break; default: return; } intelFlush( &intel->ctx ); LOCK_HARDWARE( intel ); { /* get clear bounds after locking */ cx = ctx->DrawBuffer->_Xmin; cy = ctx->DrawBuffer->_Ymin; ch = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin; cw = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin; all = (cw == ctx->DrawBuffer->Width && ch == ctx->DrawBuffer->Height); /* flip top to bottom */ cy = intel->driDrawable->h - cy - ch; cx = cx + intel->drawX; cy += intel->drawY; /* adjust for page flipping */ if ( intel->sarea->pf_current_page == 0 ) { front = intel->front_region; back = intel->back_region; } else { back = intel->front_region; front = intel->back_region; } front_pitch = front->pitch * front->cpp; back_pitch = back->pitch * back->cpp; depth_pitch = depth->pitch * depth->cpp; if (front->tiled) { FRONT_CMD |= XY_DST_TILED; front_pitch /= 4; } if (back->tiled) { BACK_CMD |= XY_DST_TILED; back_pitch /= 4; } if (depth->tiled) { DEPTH_CMD |= XY_DST_TILED; depth_pitch /= 4; } for (i = 0 ; i < intel->numClipRects ; i++) { drm_clip_rect_t *box = &intel->pClipRects[i]; drm_clip_rect_t b; if (!all) { GLint x = box->x1; GLint y = box->y1; GLint w = box->x2 - x; GLint h = box->y2 - y; if (x < cx) w -= cx - x, x = cx; if (y < cy) h -= cy - y, y = cy; if (x + w > cx + cw) w = cx + cw - x; if (y + h > cy + ch) h = cy + ch - y; if (w <= 0) continue; if (h <= 0) continue; b.x1 = x; b.y1 = y; b.x2 = x + w; b.y2 = y + h; } else { b = *box; } if (b.x1 > b.x2 || b.y1 > b.y2 || b.x2 > intelScreen->width || b.y2 > intelScreen->height) continue; if ( flags & BUFFER_BIT_FRONT_LEFT ) { BEGIN_BATCH(6, INTEL_BATCH_NO_CLIPRECTS); OUT_BATCH( FRONT_CMD ); OUT_BATCH( front_pitch | BR13 ); OUT_BATCH( (b.y1 << 16) | b.x1 ); OUT_BATCH( (b.y2 << 16) | b.x2 ); OUT_BATCH( bmBufferOffset(intel, front->buffer) ); OUT_BATCH( clear_color ); ADVANCE_BATCH(); } if ( flags & BUFFER_BIT_BACK_LEFT ) { BEGIN_BATCH(6, INTEL_BATCH_NO_CLIPRECTS); OUT_BATCH( BACK_CMD ); OUT_BATCH( back_pitch | BR13 ); OUT_BATCH( (b.y1 << 16) | b.x1 ); OUT_BATCH( (b.y2 << 16) | b.x2 ); OUT_BATCH( bmBufferOffset(intel, back->buffer) ); OUT_BATCH( clear_color ); ADVANCE_BATCH(); } if ( flags & (BUFFER_BIT_STENCIL | BUFFER_BIT_DEPTH) ) { BEGIN_BATCH(6, INTEL_BATCH_NO_CLIPRECTS); OUT_BATCH( DEPTH_CMD ); OUT_BATCH( depth_pitch | BR13 ); OUT_BATCH( (b.y1 << 16) | b.x1 ); OUT_BATCH( (b.y2 << 16) | b.x2 ); OUT_BATCH( bmBufferOffset(intel, depth->buffer) ); OUT_BATCH( clear_depth ); ADVANCE_BATCH(); } } } intel_batchbuffer_flush( intel->batch ); UNLOCK_HARDWARE( intel ); }
/** * Used to initialize the alpha value of an ARGB8888 teximage after * loading it from an XRGB8888 source. * * This is very common with glCopyTexImage2D(). */ void intel_set_teximage_alpha_to_one(struct gl_context *ctx, struct intel_texture_image *intel_image) { struct intel_context *intel = intel_context(ctx); unsigned int image_x, image_y; uint32_t x1, y1, x2, y2; uint32_t BR13, CMD; int pitch, cpp; drm_intel_bo *aper_array[2]; struct intel_region *region = intel_image->mt->region; BATCH_LOCALS; assert(intel_image->base.TexFormat == MESA_FORMAT_ARGB8888); /* get dest x/y in destination texture */ intel_miptree_get_image_offset(intel_image->mt, intel_image->level, intel_image->face, 0, &image_x, &image_y); x1 = image_x; y1 = image_y; x2 = image_x + intel_image->base.Width; y2 = image_y + intel_image->base.Height; pitch = region->pitch; cpp = region->cpp; DBG("%s dst:buf(%p)/%d %d,%d sz:%dx%d\n", __FUNCTION__, intel_image->mt->region->buffer, (pitch * cpp), x1, y1, x2 - x1, y2 - y1); BR13 = br13_for_cpp(cpp) | 0xf0 << 16; CMD = XY_COLOR_BLT_CMD; CMD |= XY_BLT_WRITE_ALPHA; assert(region->tiling != I915_TILING_Y); #ifndef I915 if (region->tiling != I915_TILING_NONE) { CMD |= XY_DST_TILED; pitch /= 4; } #endif BR13 |= (pitch * cpp); /* do space check before going any further */ aper_array[0] = intel->batch.bo; aper_array[1] = region->buffer; if (drm_intel_bufmgr_check_aperture_space(aper_array, ARRAY_SIZE(aper_array)) != 0) { intel_batchbuffer_flush(intel); } BEGIN_BATCH_BLT(6); OUT_BATCH(CMD); OUT_BATCH(BR13); OUT_BATCH((y1 << 16) | x1); OUT_BATCH((y2 << 16) | x2); OUT_RELOC_FENCED(region->buffer, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); OUT_BATCH(0xffffffff); /* white, but only alpha gets written */ ADVANCE_BATCH(); intel_batchbuffer_emit_mi_flush(intel); }
/** * Initializes potential list of extensions if ctx == NULL, or actually enables * extensions for a context. */ void intelInitExtensions(struct gl_context *ctx) { struct intel_context *intel = intel_context(ctx); assert(intel->gen == 2 || intel->gen == 3); ctx->Extensions.ARB_draw_elements_base_vertex = true; ctx->Extensions.ARB_explicit_attrib_location = true; ctx->Extensions.ARB_explicit_uniform_location = true; ctx->Extensions.ARB_framebuffer_object = true; ctx->Extensions.ARB_internalformat_query = true; ctx->Extensions.ARB_map_buffer_range = true; ctx->Extensions.ARB_point_sprite = true; ctx->Extensions.ARB_sync = true; ctx->Extensions.ARB_texture_border_clamp = true; ctx->Extensions.ARB_texture_cube_map = true; ctx->Extensions.ARB_texture_env_combine = true; ctx->Extensions.ARB_texture_env_crossbar = true; ctx->Extensions.ARB_texture_env_dot3 = true; ctx->Extensions.ARB_vertex_program = true; ctx->Extensions.ARB_vertex_shader = true; ctx->Extensions.EXT_blend_color = true; ctx->Extensions.EXT_blend_equation_separate = true; ctx->Extensions.EXT_blend_func_separate = true; ctx->Extensions.EXT_blend_minmax = true; ctx->Extensions.EXT_gpu_program_parameters = true; ctx->Extensions.EXT_pixel_buffer_object = true; ctx->Extensions.EXT_point_parameters = true; ctx->Extensions.EXT_provoking_vertex = true; ctx->Extensions.EXT_texture_env_dot3 = true; ctx->Extensions.EXT_texture_filter_anisotropic = true; ctx->Extensions.APPLE_object_purgeable = true; ctx->Extensions.MESA_pack_invert = true; ctx->Extensions.MESA_ycbcr_texture = true; ctx->Extensions.NV_texture_rectangle = true; ctx->Extensions.TDFX_texture_compression_FXT1 = true; ctx->Extensions.OES_EGL_image = true; ctx->Extensions.OES_draw_texture = true; ctx->Const.GLSLVersion = 120; _mesa_override_glsl_version(&ctx->Const); if (intel->gen >= 3) { ctx->Extensions.ARB_ES2_compatibility = true; ctx->Extensions.ARB_depth_texture = true; ctx->Extensions.ARB_fragment_program = true; ctx->Extensions.ARB_shadow = true; ctx->Extensions.ARB_texture_non_power_of_two = true; ctx->Extensions.EXT_texture_sRGB = true; ctx->Extensions.EXT_texture_sRGB_decode = true; ctx->Extensions.EXT_stencil_two_side = true; ctx->Extensions.ATI_separate_stencil = true; ctx->Extensions.ATI_texture_env_combine3 = true; ctx->Extensions.NV_texture_env_combine4 = true; ctx->Extensions.ARB_fragment_shader = true; ctx->Extensions.ARB_occlusion_query = true; } if (intel->ctx.Mesa_DXTn || driQueryOptionb(&intel->optionCache, "force_s3tc_enable")) ctx->Extensions.EXT_texture_compression_s3tc = true; ctx->Extensions.ANGLE_texture_compression_dxt = true; }
/** * Use blitting to clear the renderbuffers named by 'flags'. * Note: we can't use the ctx->DrawBuffer->_ColorDrawBufferIndexes field * since that might include software renderbuffers or renderbuffers * which we're clearing with triangles. * \param mask bitmask of BUFFER_BIT_* values indicating buffers to clear */ GLbitfield intelClearWithBlit(struct gl_context *ctx, GLbitfield mask) { struct intel_context *intel = intel_context(ctx); struct gl_framebuffer *fb = ctx->DrawBuffer; GLuint clear_depth_value, clear_depth_mask; GLint cx, cy, cw, ch; GLbitfield fail_mask = 0; BATCH_LOCALS; /* Note: we don't use this function on Gen7+ hardware, so we can safely * ignore fast color clear issues. */ assert(intel->gen < 7); /* * Compute values for clearing the buffers. */ clear_depth_value = 0; clear_depth_mask = 0; if (mask & BUFFER_BIT_DEPTH) { clear_depth_value = (GLuint) (fb->_DepthMax * ctx->Depth.Clear); clear_depth_mask = XY_BLT_WRITE_RGB; } if (mask & BUFFER_BIT_STENCIL) { clear_depth_value |= (ctx->Stencil.Clear & 0xff) << 24; clear_depth_mask |= XY_BLT_WRITE_ALPHA; } cx = fb->_Xmin; if (_mesa_is_winsys_fbo(fb)) cy = ctx->DrawBuffer->Height - fb->_Ymax; else cy = fb->_Ymin; cw = fb->_Xmax - fb->_Xmin; ch = fb->_Ymax - fb->_Ymin; if (cw == 0 || ch == 0) return 0; /* Loop over all renderbuffers */ mask &= (1 << BUFFER_COUNT) - 1; while (mask) { GLuint buf = ffs(mask) - 1; bool is_depth_stencil = buf == BUFFER_DEPTH || buf == BUFFER_STENCIL; struct intel_renderbuffer *irb; int x1, y1, x2, y2; uint32_t clear_val; uint32_t BR13, CMD; struct intel_region *region; int pitch, cpp; drm_intel_bo *aper_array[2]; mask &= ~(1 << buf); irb = intel_get_renderbuffer(fb, buf); if (irb && irb->mt) { region = irb->mt->region; assert(region); assert(region->bo); } else { fail_mask |= 1 << buf; continue; } /* OK, clear this renderbuffer */ x1 = cx + irb->draw_x; y1 = cy + irb->draw_y; x2 = cx + cw + irb->draw_x; y2 = cy + ch + irb->draw_y; pitch = region->pitch; cpp = region->cpp; DBG("%s dst:buf(%p)/%d %d,%d sz:%dx%d\n", __func__, region->bo, pitch, x1, y1, x2 - x1, y2 - y1); BR13 = 0xf0 << 16; CMD = XY_COLOR_BLT_CMD; /* Setup the blit command */ if (cpp == 4) { if (is_depth_stencil) { CMD |= clear_depth_mask; } else { /* clearing RGBA */ CMD |= XY_BLT_WRITE_ALPHA | XY_BLT_WRITE_RGB; } } assert(region->tiling != I915_TILING_Y); BR13 |= pitch; if (is_depth_stencil) { clear_val = clear_depth_value; } else { uint8_t clear[4]; GLfloat *color = ctx->Color.ClearColor.f; _mesa_unclamped_float_rgba_to_ubyte(clear, color); switch (intel_rb_format(irb)) { case MESA_FORMAT_B8G8R8A8_UNORM: case MESA_FORMAT_B8G8R8X8_UNORM: clear_val = PACK_COLOR_8888(clear[3], clear[0], clear[1], clear[2]); break; case MESA_FORMAT_B5G6R5_UNORM: clear_val = PACK_COLOR_565(clear[0], clear[1], clear[2]); break; case MESA_FORMAT_B4G4R4A4_UNORM: clear_val = PACK_COLOR_4444(clear[3], clear[0], clear[1], clear[2]); break; case MESA_FORMAT_B5G5R5A1_UNORM: clear_val = PACK_COLOR_1555(clear[3], clear[0], clear[1], clear[2]); break; case MESA_FORMAT_A_UNORM8: clear_val = PACK_COLOR_8888(clear[3], clear[3], clear[3], clear[3]); break; default: fail_mask |= 1 << buf; continue; } } BR13 |= br13_for_cpp(cpp); assert(x1 < x2); assert(y1 < y2); /* do space check before going any further */ aper_array[0] = intel->batch.bo; aper_array[1] = region->bo; if (drm_intel_bufmgr_check_aperture_space(aper_array, ARRAY_SIZE(aper_array)) != 0) { intel_batchbuffer_flush(intel); } BEGIN_BATCH(6); OUT_BATCH(CMD | (6 - 2)); OUT_BATCH(BR13); OUT_BATCH((y1 << 16) | x1); OUT_BATCH((y2 << 16) | x2); OUT_RELOC_FENCED(region->bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); OUT_BATCH(clear_val); ADVANCE_BATCH(); if (intel->always_flush_cache) intel_batchbuffer_emit_mi_flush(intel); if (buf == BUFFER_DEPTH || buf == BUFFER_STENCIL) mask &= ~(BUFFER_BIT_DEPTH | BUFFER_BIT_STENCIL); } return fail_mask; }
/** * Called via glRenderbufferStorageEXT() to set the format and allocate * storage for a user-created renderbuffer. */ static GLboolean intel_alloc_renderbuffer_storage(GLcontext * ctx, struct gl_renderbuffer *rb, GLenum internalFormat, GLuint width, GLuint height) { struct intel_context *intel = intel_context(ctx); struct intel_renderbuffer *irb = intel_renderbuffer(rb); GLboolean softwareBuffer = GL_FALSE; int cpp; ASSERT(rb->Name != 0); switch (internalFormat) { case GL_R3_G3_B2: case GL_RGB4: case GL_RGB5: rb->_ActualFormat = GL_RGB5; rb->DataType = GL_UNSIGNED_BYTE; rb->RedBits = 5; rb->GreenBits = 6; rb->BlueBits = 5; cpp = 2; break; case GL_RGB: case GL_RGB8: case GL_RGB10: case GL_RGB12: case GL_RGB16: case GL_RGBA: case GL_RGBA2: case GL_RGBA4: case GL_RGB5_A1: case GL_RGBA8: case GL_RGB10_A2: case GL_RGBA12: case GL_RGBA16: rb->_ActualFormat = GL_RGBA8; rb->DataType = GL_UNSIGNED_BYTE; rb->RedBits = 8; rb->GreenBits = 8; rb->BlueBits = 8; rb->AlphaBits = 8; cpp = 4; break; case GL_STENCIL_INDEX: case GL_STENCIL_INDEX1_EXT: case GL_STENCIL_INDEX4_EXT: case GL_STENCIL_INDEX8_EXT: case GL_STENCIL_INDEX16_EXT: /* alloc a depth+stencil buffer */ rb->_ActualFormat = GL_DEPTH24_STENCIL8_EXT; rb->DataType = GL_UNSIGNED_INT_24_8_EXT; rb->StencilBits = 8; cpp = 4; break; case GL_DEPTH_COMPONENT16: rb->_ActualFormat = GL_DEPTH_COMPONENT16; rb->DataType = GL_UNSIGNED_SHORT; rb->DepthBits = 16; cpp = 2; break; case GL_DEPTH_COMPONENT: case GL_DEPTH_COMPONENT24: case GL_DEPTH_COMPONENT32: rb->_ActualFormat = GL_DEPTH24_STENCIL8_EXT; rb->DataType = GL_UNSIGNED_INT_24_8_EXT; rb->DepthBits = 24; cpp = 4; break; case GL_DEPTH_STENCIL_EXT: case GL_DEPTH24_STENCIL8_EXT: rb->_ActualFormat = GL_DEPTH24_STENCIL8_EXT; rb->DataType = GL_UNSIGNED_INT_24_8_EXT; rb->DepthBits = 24; rb->StencilBits = 8; cpp = 4; break; default: _mesa_problem(ctx, "Unexpected format in intel_alloc_renderbuffer_storage"); return GL_FALSE; } intelFlush(ctx); /* free old region */ if (irb->region) { intel_region_release(&irb->region); } /* allocate new memory region/renderbuffer */ if (softwareBuffer) { return _mesa_soft_renderbuffer_storage(ctx, rb, internalFormat, width, height); } else { /* Choose a pitch to match hardware requirements: */ GLuint pitch = ((cpp * width + 63) & ~63) / cpp; /* alloc hardware renderbuffer */ DBG("Allocating %d x %d Intel RBO (pitch %d)\n", width, height, pitch); irb->region = intel_region_alloc(intel, cpp, pitch, height); if (!irb->region) return GL_FALSE; /* out of memory? */ ASSERT(irb->region->buffer); rb->Width = width; rb->Height = height; /* This sets the Get/PutRow/Value functions */ intel_set_span_functions(&irb->Base); return GL_TRUE; } }
int brw_prepare_vertices( struct brw_context *brw, GLuint min_index, GLuint max_index ) { GLcontext *ctx = &brw->intel.ctx; struct intel_context *intel = intel_context(ctx); GLuint tmp = brw->vs.prog_data->inputs_read; GLuint i; const unsigned char *ptr = NULL; GLuint interleave = 0; int ret = 0; struct brw_vertex_element *enabled[VERT_ATTRIB_MAX]; GLuint nr_enabled = 0; struct brw_vertex_element *upload[VERT_ATTRIB_MAX]; GLuint nr_uploads = 0; /* First build an array of pointers to ve's in vb.inputs_read */ if (0) _mesa_printf("%s %d..%d\n", __FUNCTION__, min_index, max_index); /* Accumulate the list of enabled arrays. */ while (tmp) { GLuint i = _mesa_ffsll(tmp)-1; struct brw_vertex_element *input = &brw->vb.inputs[i]; tmp &= ~(1<<i); enabled[nr_enabled++] = input; } /* XXX: In the rare cases where this happens we fallback all * the way to software rasterization, although a tnl fallback * would be sufficient. I don't know of *any* real world * cases with > 17 vertex attributes enabled, so it probably * isn't an issue at this point. */ if (nr_enabled >= BRW_VEP_MAX) return -1; for (i = 0; i < nr_enabled; i++) { struct brw_vertex_element *input = enabled[i]; input->element_size = get_size(input->glarray->Type) * input->glarray->Size; input->count = input->glarray->StrideB ? max_index + 1 - min_index : 1; if (input->glarray->BufferObj->Name != 0) { struct intel_buffer_object *intel_buffer = intel_buffer_object(input->glarray->BufferObj); /* Named buffer object: Just reference its contents directly. */ input->bo = intel_bufferobj_buffer(intel, intel_buffer, INTEL_READ); dri_bo_reference(input->bo); input->offset = (unsigned long)input->glarray->Ptr; input->stride = input->glarray->StrideB; ret |= dri_bufmgr_check_aperture_space(input->bo); } else { /* Queue the buffer object up to be uploaded in the next pass, * when we've decided if we're doing interleaved or not. */ if (i == 0) { /* Position array not properly enabled: */ if (input->glarray->StrideB == 0) return -1; interleave = input->glarray->StrideB; ptr = input->glarray->Ptr; } else if (interleave != input->glarray->StrideB || (const unsigned char *)input->glarray->Ptr - ptr < 0 || (const unsigned char *)input->glarray->Ptr - ptr > interleave) { interleave = 0; } upload[nr_uploads++] = input; /* We rebase drawing to start at element zero only when * varyings are not in vbos, which means we can end up * uploading non-varying arrays (stride != 0) when min_index * is zero. This doesn't matter as the amount to upload is * the same for these arrays whether the draw call is rebased * or not - we just have to upload the one element. */ assert(min_index == 0 || input->glarray->StrideB == 0); } } /* Handle any arrays to be uploaded. */ if (nr_uploads > 1 && interleave && interleave <= 256) { /* All uploads are interleaved, so upload the arrays together as * interleaved. First, upload the contents and set up upload[0]. */ copy_array_to_vbo_array(brw, upload[0], interleave); ret |= dri_bufmgr_check_aperture_space(upload[0]->bo); for (i = 1; i < nr_uploads; i++) { /* Then, just point upload[i] at upload[0]'s buffer. */ upload[i]->stride = interleave; upload[i]->offset = upload[0]->offset + ((const unsigned char *)upload[i]->glarray->Ptr - ptr); upload[i]->bo = upload[0]->bo; dri_bo_reference(upload[i]->bo); } } else { /* Upload non-interleaved arrays */ for (i = 0; i < nr_uploads; i++) { copy_array_to_vbo_array(brw, upload[i], upload[i]->element_size); if (upload[i]->bo) { ret |= dri_bufmgr_check_aperture_space(upload[i]->bo); } } } if (ret) return 1; return 0; }
/** * Use blitting to clear the renderbuffers named by 'flags'. * Note: we can't use the ctx->DrawBuffer->_ColorDrawBufferIndexes field * since that might include software renderbuffers or renderbuffers * which we're clearing with triangles. * \param mask bitmask of BUFFER_BIT_* values indicating buffers to clear */ void intelClearWithBlit(GLcontext *ctx, GLbitfield mask) { struct intel_context *intel = intel_context(ctx); struct gl_framebuffer *fb = ctx->DrawBuffer; GLuint clear_depth; GLbitfield skipBuffers = 0; BATCH_LOCALS; /* * Compute values for clearing the buffers. */ clear_depth = 0; if (mask & BUFFER_BIT_DEPTH) { clear_depth = (GLuint) (fb->_DepthMax * ctx->Depth.Clear); } if (mask & BUFFER_BIT_STENCIL) { clear_depth |= (ctx->Stencil.Clear & 0xff) << 24; } /* If clearing both depth and stencil, skip BUFFER_BIT_STENCIL in * the loop below. */ if ((mask & BUFFER_BIT_DEPTH) && (mask & BUFFER_BIT_STENCIL)) { skipBuffers = BUFFER_BIT_STENCIL; } /* XXX Move this flush/lock into the following conditional? */ intelFlush(&intel->ctx); LOCK_HARDWARE(intel); if (intel->numClipRects) { GLint cx, cy, cw, ch; drm_clip_rect_t clear; int i; /* Get clear bounds after locking */ cx = fb->_Xmin; cy = fb->_Ymin; cw = fb->_Xmax - cx; ch = fb->_Ymax - cy; if (fb->Name == 0) { /* clearing a window */ /* flip top to bottom */ clear.x1 = cx + intel->drawX; clear.y1 = intel->driDrawable->y + intel->driDrawable->h - cy - ch; clear.x2 = clear.x1 + cw; clear.y2 = clear.y1 + ch; } else { /* clearing FBO */ assert(intel->numClipRects == 1); assert(intel->pClipRects == &intel->fboRect); clear.x1 = cx; clear.y1 = cy; clear.x2 = clear.x1 + cw; clear.y2 = clear.y1 + ch; /* no change to mask */ } for (i = 0; i < intel->numClipRects; i++) { const drm_clip_rect_t *box = &intel->pClipRects[i]; drm_clip_rect_t b; GLuint buf; GLuint clearMask = mask; /* use copy, since we modify it below */ GLboolean all = (cw == fb->Width && ch == fb->Height); if (!all) { intel_intersect_cliprects(&b, &clear, box); } else { b = *box; } if (b.x1 >= b.x2 || b.y1 >= b.y2) continue; if (0) _mesa_printf("clear %d,%d..%d,%d, mask %x\n", b.x1, b.y1, b.x2, b.y2, mask); /* Loop over all renderbuffers */ for (buf = 0; buf < BUFFER_COUNT && clearMask; buf++) { const GLbitfield bufBit = 1 << buf; if ((clearMask & bufBit) && !(bufBit & skipBuffers)) { /* OK, clear this renderbuffer */ struct intel_region *irb_region = intel_get_rb_region(fb, buf); dri_bo *write_buffer = intel_region_buffer(intel, irb_region, all ? INTEL_WRITE_FULL : INTEL_WRITE_PART); GLuint clearVal; GLint pitch, cpp; GLuint BR13, CMD; ASSERT(irb_region); pitch = irb_region->pitch; cpp = irb_region->cpp; DBG("%s dst:buf(%p)/%d+%d %d,%d sz:%dx%d\n", __FUNCTION__, irb_region->buffer, (pitch * cpp), irb_region->draw_offset, b.x1, b.y1, b.x2 - b.x1, b.y2 - b.y1); BR13 = 0xf0 << 16; CMD = XY_COLOR_BLT_CMD; /* Setup the blit command */ if (cpp == 4) { BR13 |= (1 << 24) | (1 << 25); if (buf == BUFFER_DEPTH || buf == BUFFER_STENCIL) { if (clearMask & BUFFER_BIT_DEPTH) CMD |= XY_BLT_WRITE_RGB; if (clearMask & BUFFER_BIT_STENCIL) CMD |= XY_BLT_WRITE_ALPHA; } else { /* clearing RGBA */ CMD |= XY_BLT_WRITE_ALPHA | XY_BLT_WRITE_RGB; } } else { ASSERT(cpp == 2 || cpp == 0); BR13 |= (1 << 24); } #ifndef I915 if (irb_region->tiled) { CMD |= XY_DST_TILED; pitch /= 4; } #endif BR13 |= (pitch * cpp); if (buf == BUFFER_DEPTH || buf == BUFFER_STENCIL) { clearVal = clear_depth; } else { clearVal = (cpp == 4) ? intel->ClearColor8888 : intel->ClearColor565; } /* _mesa_debug(ctx, "hardware blit clear buf %d rb id %d\n", buf, irb->Base.Name); */ intel_wait_flips(intel); assert(b.x1 < b.x2); assert(b.y1 < b.y2); BEGIN_BATCH(6, REFERENCES_CLIPRECTS); OUT_BATCH(CMD); OUT_BATCH(BR13); OUT_BATCH((b.y1 << 16) | b.x1); OUT_BATCH((b.y2 << 16) | b.x2); OUT_RELOC(write_buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE, irb_region->draw_offset); OUT_BATCH(clearVal); ADVANCE_BATCH(); clearMask &= ~bufBit; /* turn off bit, for faster loop exit */ } } } intel_batchbuffer_flush(intel->batch); } UNLOCK_HARDWARE(intel); }
void brw_emit_vertices( struct brw_context *brw, GLuint min_index, GLuint max_index ) { GLcontext *ctx = &brw->intel.ctx; struct intel_context *intel = intel_context(ctx); GLuint tmp = brw->vs.prog_data->inputs_read; struct brw_vertex_element *enabled[VERT_ATTRIB_MAX]; GLuint i; GLuint nr_enabled = 0; /* Accumulate the list of enabled arrays. */ while (tmp) { i = _mesa_ffsll(tmp)-1; struct brw_vertex_element *input = &brw->vb.inputs[i]; tmp &= ~(1<<i); enabled[nr_enabled++] = input; } /* Now emit VB and VEP state packets. * * This still defines a hardware VB for each input, even if they * are interleaved or from the same VBO. TBD if this makes a * performance difference. */ BEGIN_BATCH(1 + nr_enabled * 4, IGNORE_CLIPRECTS); OUT_BATCH((CMD_VERTEX_BUFFER << 16) | ((1 + nr_enabled * 4) - 2)); for (i = 0; i < nr_enabled; i++) { struct brw_vertex_element *input = enabled[i]; OUT_BATCH((i << BRW_VB0_INDEX_SHIFT) | BRW_VB0_ACCESS_VERTEXDATA | (input->stride << BRW_VB0_PITCH_SHIFT)); OUT_RELOC(input->bo, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_READ, input->offset); OUT_BATCH(max_index); OUT_BATCH(0); /* Instance data step rate */ /* Unreference the buffer so it can get freed, now that we won't * touch it any more. */ dri_bo_unreference(input->bo); input->bo = NULL; } ADVANCE_BATCH(); BEGIN_BATCH(1 + nr_enabled * 2, IGNORE_CLIPRECTS); OUT_BATCH((CMD_VERTEX_ELEMENT << 16) | ((1 + nr_enabled * 2) - 2)); for (i = 0; i < nr_enabled; i++) { struct brw_vertex_element *input = enabled[i]; uint32_t format = get_surface_type(input->glarray->Type, input->glarray->Size, input->glarray->Normalized); uint32_t comp0 = BRW_VE1_COMPONENT_STORE_SRC; uint32_t comp1 = BRW_VE1_COMPONENT_STORE_SRC; uint32_t comp2 = BRW_VE1_COMPONENT_STORE_SRC; uint32_t comp3 = BRW_VE1_COMPONENT_STORE_SRC; switch (input->glarray->Size) { case 0: comp0 = BRW_VE1_COMPONENT_STORE_0; case 1: comp1 = BRW_VE1_COMPONENT_STORE_0; case 2: comp2 = BRW_VE1_COMPONENT_STORE_0; case 3: comp3 = BRW_VE1_COMPONENT_STORE_1_FLT; break; } OUT_BATCH((i << BRW_VE0_INDEX_SHIFT) | BRW_VE0_VALID | (format << BRW_VE0_FORMAT_SHIFT) | (0 << BRW_VE0_SRC_OFFSET_SHIFT)); OUT_BATCH((comp0 << BRW_VE1_COMPONENT_0_SHIFT) | (comp1 << BRW_VE1_COMPONENT_1_SHIFT) | (comp2 << BRW_VE1_COMPONENT_2_SHIFT) | (comp3 << BRW_VE1_COMPONENT_3_SHIFT) | ((i * 4) << BRW_VE1_DST_OFFSET_SHIFT)); } ADVANCE_BATCH(); }
/** * Called by ctx->Driver.Clear. */ static void intelClear(GLcontext *ctx, GLbitfield mask) { struct intel_context *intel = intel_context(ctx); const GLuint colorMask = *((GLuint *) & ctx->Color.ColorMask); GLbitfield tri_mask = 0; GLbitfield blit_mask = 0; GLbitfield swrast_mask = 0; struct gl_framebuffer *fb = ctx->DrawBuffer; GLuint i; if (0) fprintf(stderr, "%s\n", __FUNCTION__); /* HW color buffers (front, back, aux, generic FBO, etc) */ if (colorMask == ~0) { /* clear all R,G,B,A */ /* XXX FBO: need to check if colorbuffers are software RBOs! */ blit_mask |= (mask & BUFFER_BITS_COLOR); } else { /* glColorMask in effect */ tri_mask |= (mask & (BUFFER_BIT_FRONT_LEFT | BUFFER_BIT_BACK_LEFT)); } /* HW stencil */ if (mask & BUFFER_BIT_STENCIL) { const struct intel_region *stencilRegion = intel_get_rb_region(fb, BUFFER_STENCIL); if (stencilRegion) { /* have hw stencil */ if (IS_965(intel->intelScreen->deviceID) || (ctx->Stencil.WriteMask[0] & 0xff) != 0xff) { /* We have to use the 3D engine if we're clearing a partial mask * of the stencil buffer, or if we're on a 965 which has a tiled * depth/stencil buffer in a layout we can't blit to. */ tri_mask |= BUFFER_BIT_STENCIL; } else { /* clearing all stencil bits, use blitting */ blit_mask |= BUFFER_BIT_STENCIL; } } } /* HW depth */ if (mask & BUFFER_BIT_DEPTH) { /* clear depth with whatever method is used for stencil (see above) */ if (IS_965(intel->intelScreen->deviceID) || tri_mask & BUFFER_BIT_STENCIL) tri_mask |= BUFFER_BIT_DEPTH; else blit_mask |= BUFFER_BIT_DEPTH; } /* If we're doing a tri pass for depth/stencil, include a likely color * buffer with it. */ if (mask & (BUFFER_BIT_DEPTH | BUFFER_BIT_STENCIL)) { int color_bit = _mesa_ffs(mask & TRI_CLEAR_COLOR_BITS); if (color_bit != 0) { tri_mask |= blit_mask & (1 << (color_bit - 1)); blit_mask &= ~(1 << (color_bit - 1)); } } /* SW fallback clearing */ swrast_mask = mask & ~tri_mask & ~blit_mask; for (i = 0; i < BUFFER_COUNT; i++) { GLuint bufBit = 1 << i; if ((blit_mask | tri_mask) & bufBit) { if (!fb->Attachment[i].Renderbuffer->ClassID) { blit_mask &= ~bufBit; tri_mask &= ~bufBit; swrast_mask |= bufBit; } } } if (blit_mask) { if (INTEL_DEBUG & DEBUG_BLIT) { DBG("blit clear:"); for (i = 0; i < BUFFER_COUNT; i++) { if (blit_mask & (1 << i)) DBG(" %s", buffer_names[i]); } DBG("\n"); } intelClearWithBlit(ctx, blit_mask); } if (tri_mask) { if (INTEL_DEBUG & DEBUG_BLIT) { DBG("tri clear:"); for (i = 0; i < BUFFER_COUNT; i++) { if (tri_mask & (1 << i)) DBG(" %s", buffer_names[i]); } DBG("\n"); } intel_clear_tris(ctx, tri_mask); } if (swrast_mask) { if (INTEL_DEBUG & DEBUG_BLIT) { DBG("swrast clear:"); for (i = 0; i < BUFFER_COUNT; i++) { if (swrast_mask & (1 << i)) DBG(" %s", buffer_names[i]); } DBG("\n"); } _swrast_Clear(ctx, swrast_mask); } }
/** * Called by glFramebufferTexture[123]DEXT() (and other places) to * prepare for rendering into texture memory. This might be called * many times to choose different texture levels, cube faces, etc * before intel_finish_render_texture() is ever called. */ static void intel_render_texture(struct gl_context * ctx, struct gl_framebuffer *fb, struct gl_renderbuffer_attachment *att) { struct intel_context *intel = intel_context(ctx); struct gl_texture_image *image = _mesa_get_attachment_teximage(att); struct intel_renderbuffer *irb = intel_renderbuffer(att->Renderbuffer); struct intel_texture_image *intel_image = intel_texture_image(image); struct intel_mipmap_tree *mt = intel_image->mt; int layer; (void) fb; if (att->CubeMapFace > 0) { assert(att->Zoffset == 0); layer = att->CubeMapFace; } else { layer = att->Zoffset; } if (!intel_image->mt) { /* Fallback on drawing to a texture that doesn't have a miptree * (has a border, width/height 0, etc.) */ _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); _swrast_render_texture(ctx, fb, att); return; } else if (!irb) { intel_miptree_check_level_layer(mt, att->TextureLevel, layer); irb = (struct intel_renderbuffer *)intel_new_renderbuffer(ctx, ~0); if (irb) { /* bind the wrapper to the attachment point */ _mesa_reference_renderbuffer(&att->Renderbuffer, &irb->Base.Base); } else { /* fallback to software rendering */ _swrast_render_texture(ctx, fb, att); return; } } if (!intel_renderbuffer_update_wrapper(intel, irb, image, layer)) { _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); _swrast_render_texture(ctx, fb, att); return; } DBG("Begin render %s texture tex=%u w=%d h=%d refcount=%d\n", _mesa_get_format_name(image->TexFormat), att->Texture->Name, image->Width, image->Height, irb->Base.Base.RefCount); intel_image->used_as_render_target = true; #ifndef I915 if (need_tile_offset_workaround(brw_context(ctx), irb)) { /* Original gen4 hardware couldn't draw to a non-tile-aligned * destination in a miptree unless you actually setup your * renderbuffer as a miptree and used the fragile * lod/array_index/etc. controls to select the image. So, * instead, we just make a new single-level miptree and render * into that. */ struct intel_context *intel = intel_context(ctx); struct intel_mipmap_tree *new_mt; int width, height, depth; intel_miptree_get_dimensions_for_image(image, &width, &height, &depth); new_mt = intel_miptree_create(intel, image->TexObject->Target, intel_image->base.Base.TexFormat, intel_image->base.Base.Level, intel_image->base.Base.Level, width, height, depth, true); intel_miptree_copy_teximage(intel, intel_image, new_mt); intel_renderbuffer_set_draw_offset(irb); intel_miptree_reference(&irb->mt, intel_image->mt); intel_miptree_release(&new_mt); } #endif /* update drawing region, etc */ intel_draw_buffer(ctx); }
/** * Replace data in a subrange of buffer object. If the data range * specified by size + offset extends beyond the end of the buffer or * if data is NULL, no copy is performed. * Called via glBufferSubDataARB(). */ static void intel_bufferobj_subdata(struct gl_context * ctx, GLintptrARB offset, GLsizeiptrARB size, const GLvoid * data, struct gl_buffer_object *obj) { struct intel_context *intel = intel_context(ctx); struct intel_buffer_object *intel_obj = intel_buffer_object(obj); bool busy; if (size == 0) return; assert(intel_obj); /* If we have a single copy in system memory, update that */ if (intel_obj->sys_buffer) { if (intel_obj->source) release_buffer(intel_obj); if (intel_obj->buffer == NULL) { memcpy((char *)intel_obj->sys_buffer + offset, data, size); return; } free(intel_obj->sys_buffer); intel_obj->sys_buffer = NULL; } /* Otherwise we need to update the copy in video memory. */ busy = drm_intel_bo_busy(intel_obj->buffer) || drm_intel_bo_references(intel->batch.bo, intel_obj->buffer); /* replace the current busy bo with fresh data */ if (busy && size == intel_obj->Base.Size) { drm_intel_bo_unreference(intel_obj->buffer); intel_bufferobj_alloc_buffer(intel, intel_obj); drm_intel_bo_subdata(intel_obj->buffer, 0, size, data); } else if (intel->gen < 6) { if (busy) { drm_intel_bo *temp_bo; temp_bo = drm_intel_bo_alloc(intel->bufmgr, "subdata temp", size, 64); drm_intel_bo_subdata(temp_bo, 0, size, data); intel_emit_linear_blit(intel, intel_obj->buffer, offset, temp_bo, 0, size); drm_intel_bo_unreference(temp_bo); } else { drm_intel_bo_subdata(intel_obj->buffer, offset, size, data); } } else { /* Can't use the blit to modify the buffer in the middle of batch. */ if (drm_intel_bo_references(intel->batch.bo, intel_obj->buffer)) { intel_batchbuffer_flush(intel); } drm_intel_bo_subdata(intel_obj->buffer, offset, size, data); } }
/** * Do additional "completeness" testing of a framebuffer object. */ static void intel_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb) { struct intel_context *intel = intel_context(ctx); const struct intel_renderbuffer *depthRb = intel_get_renderbuffer(fb, BUFFER_DEPTH); const struct intel_renderbuffer *stencilRb = intel_get_renderbuffer(fb, BUFFER_STENCIL); struct intel_mipmap_tree *depth_mt = NULL, *stencil_mt = NULL; int i; if (depthRb) depth_mt = depthRb->mt; if (stencilRb) { stencil_mt = stencilRb->mt; if (stencil_mt->stencil_mt) stencil_mt = stencil_mt->stencil_mt; } if (depth_mt && stencil_mt) { if (depth_mt == stencil_mt) { /* For true packed depth/stencil (not faked on prefers-separate-stencil * hardware) we need to be sure they're the same level/layer, since * we'll be emitting a single packet describing the packed setup. */ if (depthRb->mt_level != stencilRb->mt_level || depthRb->mt_layer != stencilRb->mt_layer) { fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; } } else { if (!intel->has_separate_stencil) fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; if (stencil_mt->format != MESA_FORMAT_S8) fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; if (intel->gen < 7 && depth_mt->hiz_mt == NULL) { /* Before Gen7, separate depth and stencil buffers can be used * only if HiZ is enabled. From the Sandybridge PRM, Volume 2, * Part 1, Bit 3DSTATE_DEPTH_BUFFER.SeparateStencilBufferEnable: * [DevSNB]: This field must be set to the same value (enabled * or disabled) as Hierarchical Depth Buffer Enable. */ fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED; } } } for (i = 0; i < Elements(fb->Attachment); i++) { struct gl_renderbuffer *rb; struct intel_renderbuffer *irb; if (fb->Attachment[i].Type == GL_NONE) continue; /* A supported attachment will have a Renderbuffer set either * from being a Renderbuffer or being a texture that got the * intel_wrap_texture() treatment. */ rb = fb->Attachment[i].Renderbuffer; if (rb == NULL) { DBG("attachment without renderbuffer\n"); fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; continue; } if (fb->Attachment[i].Type == GL_TEXTURE) { const struct gl_texture_image *img = _mesa_get_attachment_teximage_const(&fb->Attachment[i]); if (img->Border) { DBG("texture with border\n"); fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; continue; } } irb = intel_renderbuffer(rb); if (irb == NULL) { DBG("software rendering renderbuffer\n"); fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; continue; } if (!intel->vtbl.render_target_supported(intel, rb)) { DBG("Unsupported HW texture/renderbuffer format attached: %s\n", _mesa_get_format_name(intel_rb_format(irb))); fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; } } }
static const GLubyte * intelGetString(struct gl_context * ctx, GLenum name) { const struct intel_context *const intel = intel_context(ctx); const char *chipset; static char buffer[128]; switch (name) { case GL_VENDOR: return (GLubyte *) "Intel Open Source Technology Center"; break; case GL_RENDERER: switch (intel->intelScreen->deviceID) { case PCI_CHIP_845_G: chipset = "Intel(R) 845G"; break; case PCI_CHIP_I830_M: chipset = "Intel(R) 830M"; break; case PCI_CHIP_I855_GM: chipset = "Intel(R) 852GM/855GM"; break; case PCI_CHIP_I865_G: chipset = "Intel(R) 865G"; break; case PCI_CHIP_I915_G: chipset = "Intel(R) 915G"; break; case PCI_CHIP_E7221_G: chipset = "Intel (R) E7221G (i915)"; break; case PCI_CHIP_I915_GM: chipset = "Intel(R) 915GM"; break; case PCI_CHIP_I945_G: chipset = "Intel(R) 945G"; break; case PCI_CHIP_I945_GM: chipset = "Intel(R) 945GM"; break; case PCI_CHIP_I945_GME: chipset = "Intel(R) 945GME"; break; case PCI_CHIP_G33_G: chipset = "Intel(R) G33"; break; case PCI_CHIP_Q35_G: chipset = "Intel(R) Q35"; break; case PCI_CHIP_Q33_G: chipset = "Intel(R) Q33"; break; case PCI_CHIP_IGD_GM: case PCI_CHIP_IGD_G: chipset = "Intel(R) IGD"; break; case PCI_CHIP_I965_Q: chipset = "Intel(R) 965Q"; break; case PCI_CHIP_I965_G: case PCI_CHIP_I965_G_1: chipset = "Intel(R) 965G"; break; case PCI_CHIP_I946_GZ: chipset = "Intel(R) 946GZ"; break; case PCI_CHIP_I965_GM: chipset = "Intel(R) 965GM"; break; case PCI_CHIP_I965_GME: chipset = "Intel(R) 965GME/GLE"; break; case PCI_CHIP_GM45_GM: chipset = "Mobile Intel® GM45 Express Chipset"; break; case PCI_CHIP_IGD_E_G: chipset = "Intel(R) Integrated Graphics Device"; break; case PCI_CHIP_G45_G: chipset = "Intel(R) G45/G43"; break; case PCI_CHIP_Q45_G: chipset = "Intel(R) Q45/Q43"; break; case PCI_CHIP_G41_G: chipset = "Intel(R) G41"; break; case PCI_CHIP_B43_G: case PCI_CHIP_B43_G1: chipset = "Intel(R) B43"; break; case PCI_CHIP_ILD_G: chipset = "Intel(R) Ironlake Desktop"; break; case PCI_CHIP_ILM_G: chipset = "Intel(R) Ironlake Mobile"; break; case PCI_CHIP_SANDYBRIDGE_GT1: case PCI_CHIP_SANDYBRIDGE_GT2: case PCI_CHIP_SANDYBRIDGE_GT2_PLUS: chipset = "Intel(R) Sandybridge Desktop"; break; case PCI_CHIP_SANDYBRIDGE_M_GT1: case PCI_CHIP_SANDYBRIDGE_M_GT2: case PCI_CHIP_SANDYBRIDGE_M_GT2_PLUS: chipset = "Intel(R) Sandybridge Mobile"; break; case PCI_CHIP_SANDYBRIDGE_S: chipset = "Intel(R) Sandybridge Server"; break; case PCI_CHIP_IVYBRIDGE_GT1: case PCI_CHIP_IVYBRIDGE_GT2: chipset = "Intel(R) Ivybridge Desktop"; break; case PCI_CHIP_IVYBRIDGE_M_GT1: case PCI_CHIP_IVYBRIDGE_M_GT2: chipset = "Intel(R) Ivybridge Mobile"; break; case PCI_CHIP_IVYBRIDGE_S_GT1: case PCI_CHIP_IVYBRIDGE_S_GT2: chipset = "Intel(R) Ivybridge Server"; break; case PCI_CHIP_HASWELL_GT1: case PCI_CHIP_HASWELL_GT2: case PCI_CHIP_HASWELL_GT2_PLUS: case PCI_CHIP_HASWELL_SDV_GT1: case PCI_CHIP_HASWELL_SDV_GT2: case PCI_CHIP_HASWELL_SDV_GT2_PLUS: case PCI_CHIP_HASWELL_ULT_GT1: case PCI_CHIP_HASWELL_ULT_GT2: case PCI_CHIP_HASWELL_ULT_GT2_PLUS: case PCI_CHIP_HASWELL_CRW_GT1: case PCI_CHIP_HASWELL_CRW_GT2: case PCI_CHIP_HASWELL_CRW_GT2_PLUS: chipset = "Intel(R) Haswell Desktop"; break; case PCI_CHIP_HASWELL_M_GT1: case PCI_CHIP_HASWELL_M_GT2: case PCI_CHIP_HASWELL_M_GT2_PLUS: case PCI_CHIP_HASWELL_SDV_M_GT1: case PCI_CHIP_HASWELL_SDV_M_GT2: case PCI_CHIP_HASWELL_SDV_M_GT2_PLUS: case PCI_CHIP_HASWELL_ULT_M_GT1: case PCI_CHIP_HASWELL_ULT_M_GT2: case PCI_CHIP_HASWELL_ULT_M_GT2_PLUS: case PCI_CHIP_HASWELL_CRW_M_GT1: case PCI_CHIP_HASWELL_CRW_M_GT2: case PCI_CHIP_HASWELL_CRW_M_GT2_PLUS: chipset = "Intel(R) Haswell Mobile"; break; case PCI_CHIP_HASWELL_S_GT1: case PCI_CHIP_HASWELL_S_GT2: case PCI_CHIP_HASWELL_S_GT2_PLUS: case PCI_CHIP_HASWELL_SDV_S_GT1: case PCI_CHIP_HASWELL_SDV_S_GT2: case PCI_CHIP_HASWELL_SDV_S_GT2_PLUS: case PCI_CHIP_HASWELL_ULT_S_GT1: case PCI_CHIP_HASWELL_ULT_S_GT2: case PCI_CHIP_HASWELL_ULT_S_GT2_PLUS: case PCI_CHIP_HASWELL_CRW_S_GT1: case PCI_CHIP_HASWELL_CRW_S_GT2: case PCI_CHIP_HASWELL_CRW_S_GT2_PLUS: chipset = "Intel(R) Haswell Server"; break; default: chipset = "Unknown Intel Chipset"; break; } (void) driGetRendererString(buffer, chipset, 0); return (GLubyte *) buffer; default: return NULL; } }
/** * Do additional "completeness" testing of a framebuffer object. */ static void intel_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb) { struct intel_context *intel = intel_context(ctx); struct intel_renderbuffer *depthRb = intel_get_renderbuffer(fb, BUFFER_DEPTH); struct intel_renderbuffer *stencilRb = intel_get_renderbuffer(fb, BUFFER_STENCIL); struct intel_mipmap_tree *depth_mt = NULL, *stencil_mt = NULL; int i; DBG("%s() on fb %p (%s)\n", __FUNCTION__, fb, (fb == ctx->DrawBuffer ? "drawbuffer" : (fb == ctx->ReadBuffer ? "readbuffer" : "other buffer"))); if (depthRb) depth_mt = depthRb->mt; if (stencilRb) stencil_mt = stencilRb->mt; if (depth_mt && stencil_mt) { /* Make sure that the depth and stencil buffers are actually the same * slice of the same miptree, since we only support packed * depth/stencil. */ if (depth_mt == stencil_mt) { if (depthRb->mt_level != stencilRb->mt_level || depthRb->mt_layer != stencilRb->mt_layer) { fbo_incomplete(fb, "FBO incomplete: depth image level/layer %d/%d != " "stencil image %d/%d\n", depthRb->mt_level, depthRb->mt_layer, stencilRb->mt_level, stencilRb->mt_layer); } } else { fbo_incomplete(fb, "FBO incomplete: separate stencil unsupported\n"); } } for (i = 0; i < Elements(fb->Attachment); i++) { struct gl_renderbuffer *rb; struct intel_renderbuffer *irb; if (fb->Attachment[i].Type == GL_NONE) continue; /* A supported attachment will have a Renderbuffer set either * from being a Renderbuffer or being a texture that got the * intel_wrap_texture() treatment. */ rb = fb->Attachment[i].Renderbuffer; if (rb == NULL) { fbo_incomplete(fb, "FBO incomplete: attachment without " "renderbuffer\n"); continue; } if (fb->Attachment[i].Type == GL_TEXTURE) { if (rb->TexImage->Border) { fbo_incomplete(fb, "FBO incomplete: texture with border\n"); continue; } } irb = intel_renderbuffer(rb); if (irb == NULL) { fbo_incomplete(fb, "FBO incomplete: software rendering " "renderbuffer\n"); continue; } if (!intel->vtbl.render_target_supported(intel, rb)) { fbo_incomplete(fb, "FBO incomplete: Unsupported HW " "texture/renderbuffer format attached: %s\n", _mesa_get_format_name(intel_rb_format(irb))); } } }