static GLboolean enable_tex_common( GLcontext *ctx, GLuint unit ) { i915ContextPtr i915 = I915_CONTEXT(ctx); struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; struct gl_texture_object *tObj = texUnit->_Current; i915TextureObjectPtr t = (i915TextureObjectPtr)tObj->DriverData; if (0) fprintf(stderr, "%s %d\n", __FUNCTION__, unit); if (!(i915->state.active & I915_UPLOAD_TEX(unit))) { I915_ACTIVESTATE(i915, I915_UPLOAD_TEX(unit), GL_TRUE); } /* Fallback if there's a texture border */ if ( tObj->Image[0][tObj->BaseLevel]->Border > 0 ) { return GL_FALSE; } /* Update state if this is a different texture object to last * time. */ if (i915->intel.CurrentTexObj[unit] != &t->intel || (t->intel.dirty & I915_UPLOAD_TEX(unit))) { i915_import_tex_unit( i915, t, unit); i915->tex_program.translated = 0; } return GL_TRUE; }
static GLboolean enable_tex_2d( GLcontext *ctx, GLuint unit ) { i915ContextPtr i915 = I915_CONTEXT(ctx); struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; struct gl_texture_object *tObj = texUnit->_Current; i915TextureObjectPtr t = (i915TextureObjectPtr)tObj->DriverData; GLuint ss3 = i915->state.Tex[unit][I915_TEXREG_SS3]; ss3 |= SS3_NORMALIZED_COORDS; if (ss3 != i915->state.Tex[unit][I915_TEXREG_SS3]) { I915_STATECHANGE(i915, I915_UPLOAD_TEX(unit)); i915->state.Tex[unit][I915_TEXREG_SS3] = ss3; } /* Upload teximages (not pipelined) */ if (t->intel.base.dirty_images[0]) { i915SetTexImages( i915, tObj ); if (!intelUploadTexImages( &i915->intel, &t->intel, 0 )) { return GL_FALSE; } } return GL_TRUE; }
static GLboolean disable_tex( GLcontext *ctx, GLuint unit ) { i915ContextPtr i915 = I915_CONTEXT(ctx); if (i915->state.active & I915_UPLOAD_TEX(unit)) { I915_ACTIVESTATE(i915, I915_UPLOAD_TEX(unit), GL_FALSE); } /* The old texture is no longer bound to this texture unit. * Mark it as such. */ if ( i915->intel.CurrentTexObj[unit] != NULL ) { i915->intel.CurrentTexObj[unit]->base.bound &= ~(1U << 0); i915->intel.CurrentTexObj[unit] = NULL; } return GL_TRUE; }
static void i915_import_tex_unit( i915ContextPtr i915, i915TextureObjectPtr t, GLuint unit ) { GLuint state[I915_TEX_SETUP_SIZE]; if(INTEL_DEBUG&DEBUG_TEXTURE) fprintf(stderr, "%s unit(%d)\n", __FUNCTION__, unit); if (i915->intel.CurrentTexObj[unit]) i915->intel.CurrentTexObj[unit]->base.bound &= ~(1U << unit); i915->intel.CurrentTexObj[unit] = (intelTextureObjectPtr)t; t->intel.base.bound |= (1 << unit); if (t->intel.dirty & I915_UPLOAD_TEX(unit)) { i915ImportTexObjState( t->intel.base.tObj ); t->intel.dirty &= ~I915_UPLOAD_TEX(unit); } state[I915_TEXREG_MS2] = t->intel.TextureOffset; state[I915_TEXREG_MS3] = t->Setup[I915_TEXREG_MS3]; state[I915_TEXREG_MS4] = t->Setup[I915_TEXREG_MS4]; state[I915_TEXREG_SS2] = (i915->state.Tex[unit][I915_TEXREG_SS2] & SS2_LOD_BIAS_MASK); state[I915_TEXREG_SS2] |= (t->Setup[I915_TEXREG_SS2] & ~SS2_LOD_BIAS_MASK); state[I915_TEXREG_SS3] = (i915->state.Tex[unit][I915_TEXREG_SS3] & SS3_NORMALIZED_COORDS); state[I915_TEXREG_SS3] |= (t->Setup[I915_TEXREG_SS3] & ~(SS3_NORMALIZED_COORDS| SS3_TEXTUREMAP_INDEX_MASK)); state[I915_TEXREG_SS3] |= (unit<<SS3_TEXTUREMAP_INDEX_SHIFT); state[I915_TEXREG_SS4] = t->Setup[I915_TEXREG_SS4]; if (memcmp(state, i915->state.Tex[unit], sizeof(state)) != 0) { I915_STATECHANGE( i915, I915_UPLOAD_TEX(unit) ); memcpy(i915->state.Tex[unit], state, sizeof(state)); } }
void i915UpdateTextureState(struct intel_context *intel) { GLboolean ok = GL_TRUE; GLuint i; for (i = 0; i < I915_TEX_UNITS && ok; i++) { switch (intel->ctx.Texture.Unit[i]._ReallyEnabled) { case TEXTURE_1D_BIT: case TEXTURE_2D_BIT: case TEXTURE_CUBE_BIT: case TEXTURE_3D_BIT: ok = i915_update_tex_unit(intel, i, SS3_NORMALIZED_COORDS); break; case TEXTURE_RECT_BIT: ok = i915_update_tex_unit(intel, i, 0); break; case 0:{ struct i915_context *i915 = i915_context(&intel->ctx); if (i915->state.active & I915_UPLOAD_TEX(i)) I915_ACTIVESTATE(i915, I915_UPLOAD_TEX(i), GL_FALSE); if (i915->state.tex_buffer[i] != NULL) { drm_intel_bo_unreference(i915->state.tex_buffer[i]); i915->state.tex_buffer[i] = NULL; } break; } default: ok = GL_FALSE; break; } } FALLBACK(intel, I915_FALLBACK_TEXTURE, !ok); }
static void i915TexEnv( GLcontext *ctx, GLenum target, GLenum pname, const GLfloat *param ) { i915ContextPtr i915 = I915_CONTEXT( ctx ); GLuint unit = ctx->Texture.CurrentUnit; switch (pname) { case GL_TEXTURE_ENV_COLOR: /* Should be a tracked param */ case GL_TEXTURE_ENV_MODE: case GL_COMBINE_RGB: case GL_COMBINE_ALPHA: case GL_SOURCE0_RGB: case GL_SOURCE1_RGB: case GL_SOURCE2_RGB: case GL_SOURCE0_ALPHA: case GL_SOURCE1_ALPHA: case GL_SOURCE2_ALPHA: case GL_OPERAND0_RGB: case GL_OPERAND1_RGB: case GL_OPERAND2_RGB: case GL_OPERAND0_ALPHA: case GL_OPERAND1_ALPHA: case GL_OPERAND2_ALPHA: case GL_RGB_SCALE: case GL_ALPHA_SCALE: i915->tex_program.translated = 0; break; case GL_TEXTURE_LOD_BIAS: { int b = (int) ((*param) * 16.0); if (b > 255) b = 255; if (b < -256) b = -256; I915_STATECHANGE(i915, I915_UPLOAD_TEX(unit)); i915->state.Tex[unit][I915_TEXREG_SS2] &= ~SS2_LOD_BIAS_MASK; i915->state.Tex[unit][I915_TEXREG_SS2] |= ((b << SS2_LOD_BIAS_SHIFT) & SS2_LOD_BIAS_MASK); break; } default: break; } }
static GLuint get_state_size(struct i915_hw_state *state) { GLuint dirty = get_dirty(state); GLuint i; GLuint sz = 0; if (dirty & I915_UPLOAD_INVARIENT) sz += 30 * 4; if (dirty & I915_UPLOAD_RASTER_RULES) sz += sizeof(state->RasterRules); if (dirty & I915_UPLOAD_CTX) sz += sizeof(state->Ctx); if (dirty & I915_UPLOAD_BLEND) sz += sizeof(state->Blend); if (dirty & I915_UPLOAD_BUFFERS) sz += sizeof(state->Buffer); if (dirty & I915_UPLOAD_STIPPLE) sz += sizeof(state->Stipple); if (dirty & I915_UPLOAD_TEX_ALL) { int nr = 0; for (i = 0; i < I915_TEX_UNITS; i++) if (dirty & I915_UPLOAD_TEX(i)) nr++; sz += (2 + nr * 3) * sizeof(GLuint) * 2; } if (dirty & I915_UPLOAD_CONSTANTS) sz += state->ConstantSize * sizeof(GLuint); if (dirty & I915_UPLOAD_PROGRAM) sz += state->ProgramSize * sizeof(GLuint); return sz; }
static GLuint get_state_size(struct i915_hw_state *state) { GLuint dirty = get_dirty(state); GLuint i; GLuint sz = 0; if (dirty & I915_UPLOAD_CTX) sz += sizeof(state->Ctx); if (dirty & I915_UPLOAD_BUFFERS) sz += sizeof(state->Buffer); if (dirty & I915_UPLOAD_STIPPLE) sz += sizeof(state->Stipple); if (dirty & I915_UPLOAD_FOG) sz += sizeof(state->Fog); if (dirty & I915_UPLOAD_TEX_ALL) { int nr = 0; for (i = 0; i < I915_TEX_UNITS; i++) if (dirty & I915_UPLOAD_TEX(i)) nr++; sz += (2 + nr * 3) * sizeof(GLuint) * 2; } if (dirty & I915_UPLOAD_CONSTANTS) sz += state->ConstantSize * sizeof(GLuint); if (dirty & I915_UPLOAD_PROGRAM) sz += state->ProgramSize * sizeof(GLuint); return sz; }
/* Push the state into the sarea and/or texture memory. */ static void i915_emit_state(struct intel_context *intel) { struct i915_context *i915 = i915_context(&intel->ctx); struct i915_hw_state *state = &i915->state; int i, count, aper_count; GLuint dirty; drm_intel_bo *aper_array[3 + I915_TEX_UNITS]; GET_CURRENT_CONTEXT(ctx); BATCH_LOCALS; /* We don't hold the lock at this point, so want to make sure that * there won't be a buffer wrap between the state emits and the primitive * emit header. * * It might be better to talk about explicit places where * scheduling is allowed, rather than assume that it is whenever a * batchbuffer fills up. */ intel_batchbuffer_require_space(intel, get_state_size(state) + INTEL_PRIM_EMIT_SIZE); count = 0; again: if (intel->batch.bo == NULL) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "i915 emit state"); assert(0); } aper_count = 0; dirty = get_dirty(state); aper_array[aper_count++] = intel->batch.bo; if (dirty & I915_UPLOAD_BUFFERS) { if (state->draw_region) aper_array[aper_count++] = state->draw_region->bo; if (state->depth_region) aper_array[aper_count++] = state->depth_region->bo; } if (dirty & I915_UPLOAD_TEX_ALL) { for (i = 0; i < I915_TEX_UNITS; i++) { if (dirty & I915_UPLOAD_TEX(i)) { if (state->tex_buffer[i]) { aper_array[aper_count++] = state->tex_buffer[i]; } } } } if (dri_bufmgr_check_aperture_space(aper_array, aper_count)) { if (count == 0) { count++; intel_batchbuffer_flush(intel); goto again; } else { _mesa_error(ctx, GL_OUT_OF_MEMORY, "i915 emit state"); assert(0); } } /* work out list of buffers to emit */ /* Do this here as we may have flushed the batchbuffer above, * causing more state to be dirty! */ dirty = get_dirty(state); state->emitted |= dirty; assert(get_dirty(state) == 0); if (INTEL_DEBUG & DEBUG_STATE) fprintf(stderr, "%s dirty: %x\n", __FUNCTION__, dirty); if (dirty & I915_UPLOAD_INVARIENT) { if (INTEL_DEBUG & DEBUG_STATE) fprintf(stderr, "I915_UPLOAD_INVARIENT:\n"); i915_emit_invarient_state(intel); } if (dirty & I915_UPLOAD_RASTER_RULES) { if (INTEL_DEBUG & DEBUG_STATE) fprintf(stderr, "I915_UPLOAD_RASTER_RULES:\n"); emit(intel, state->RasterRules, sizeof(state->RasterRules)); } if (dirty & I915_UPLOAD_CTX) { if (INTEL_DEBUG & DEBUG_STATE) fprintf(stderr, "I915_UPLOAD_CTX:\n"); emit(intel, state->Ctx, sizeof(state->Ctx)); } if (dirty & I915_UPLOAD_BLEND) { if (INTEL_DEBUG & DEBUG_STATE) fprintf(stderr, "I915_UPLOAD_BLEND:\n"); emit(intel, state->Blend, sizeof(state->Blend)); } if (dirty & I915_UPLOAD_BUFFERS) { GLuint count; if (INTEL_DEBUG & DEBUG_STATE) fprintf(stderr, "I915_UPLOAD_BUFFERS:\n"); count = 17; if (state->Buffer[I915_DESTREG_DRAWRECT0] != MI_NOOP) count++; BEGIN_BATCH(count); OUT_BATCH(state->Buffer[I915_DESTREG_CBUFADDR0]); OUT_BATCH(state->Buffer[I915_DESTREG_CBUFADDR1]); if (state->draw_region) { OUT_RELOC(state->draw_region->bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); } else { OUT_BATCH(0); } OUT_BATCH(state->Buffer[I915_DESTREG_DBUFADDR0]); OUT_BATCH(state->Buffer[I915_DESTREG_DBUFADDR1]); if (state->depth_region) { OUT_RELOC(state->depth_region->bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); } else { OUT_BATCH(0); } OUT_BATCH(state->Buffer[I915_DESTREG_DV0]); OUT_BATCH(state->Buffer[I915_DESTREG_DV1]); OUT_BATCH(state->Buffer[I915_DESTREG_SR0]); OUT_BATCH(state->Buffer[I915_DESTREG_SR1]); OUT_BATCH(state->Buffer[I915_DESTREG_SR2]); OUT_BATCH(state->Buffer[I915_DESTREG_SENABLE]); if (state->Buffer[I915_DESTREG_DRAWRECT0] != MI_NOOP) OUT_BATCH(state->Buffer[I915_DESTREG_DRAWRECT0]); OUT_BATCH(state->Buffer[I915_DESTREG_DRAWRECT1]); OUT_BATCH(state->Buffer[I915_DESTREG_DRAWRECT2]); OUT_BATCH(state->Buffer[I915_DESTREG_DRAWRECT3]); OUT_BATCH(state->Buffer[I915_DESTREG_DRAWRECT4]); OUT_BATCH(state->Buffer[I915_DESTREG_DRAWRECT5]); ADVANCE_BATCH(); } if (dirty & I915_UPLOAD_STIPPLE) { if (INTEL_DEBUG & DEBUG_STATE) fprintf(stderr, "I915_UPLOAD_STIPPLE:\n"); emit(intel, state->Stipple, sizeof(state->Stipple)); } /* Combine all the dirty texture state into a single command to * avoid lockups on I915 hardware. */ if (dirty & I915_UPLOAD_TEX_ALL) { int nr = 0; GLuint unwind; for (i = 0; i < I915_TEX_UNITS; i++) if (dirty & I915_UPLOAD_TEX(i)) nr++; BEGIN_BATCH(2 + nr * 3); OUT_BATCH(_3DSTATE_MAP_STATE | (3 * nr)); OUT_BATCH((dirty & I915_UPLOAD_TEX_ALL) >> I915_UPLOAD_TEX_0_SHIFT); for (i = 0; i < I915_TEX_UNITS; i++) if (dirty & I915_UPLOAD_TEX(i)) { OUT_RELOC(state->tex_buffer[i], I915_GEM_DOMAIN_SAMPLER, 0, state->tex_offset[i]); OUT_BATCH(state->Tex[i][I915_TEXREG_MS3]); OUT_BATCH(state->Tex[i][I915_TEXREG_MS4]); } ADVANCE_BATCH(); unwind = intel->batch.used; BEGIN_BATCH(2 + nr * 3); OUT_BATCH(_3DSTATE_SAMPLER_STATE | (3 * nr)); OUT_BATCH((dirty & I915_UPLOAD_TEX_ALL) >> I915_UPLOAD_TEX_0_SHIFT); for (i = 0; i < I915_TEX_UNITS; i++) if (dirty & I915_UPLOAD_TEX(i)) { OUT_BATCH(state->Tex[i][I915_TEXREG_SS2]); OUT_BATCH(state->Tex[i][I915_TEXREG_SS3]); OUT_BATCH(state->Tex[i][I915_TEXREG_SS4]); } ADVANCE_BATCH(); if (i915->last_sampler && memcmp(intel->batch.map + i915->last_sampler, intel->batch.map + unwind, (2 + nr*3)*sizeof(int)) == 0) intel->batch.used = unwind; else i915->last_sampler = unwind; }
/* Recalculate all state from scratch. Perhaps not the most * efficient, but this has gotten complex enough that we need * something which is understandable and reliable. */ static GLboolean i915_update_tex_unit(struct intel_context *intel, GLuint unit, GLuint ss3) { struct gl_context *ctx = &intel->ctx; struct i915_context *i915 = i915_context(ctx); struct gl_texture_unit *tUnit = &ctx->Texture.Unit[unit]; struct gl_texture_object *tObj = tUnit->_Current; struct intel_texture_object *intelObj = intel_texture_object(tObj); struct gl_texture_image *firstImage; GLuint *state = i915->state.Tex[unit], format, pitch; GLint lodbias, aniso = 0; GLubyte border[4]; GLfloat maxlod; memset(state, 0, sizeof(state)); /*We need to refcount these. */ if (i915->state.tex_buffer[unit] != NULL) { drm_intel_bo_unreference(i915->state.tex_buffer[unit]); i915->state.tex_buffer[unit] = NULL; } if (!intel_finalize_mipmap_tree(intel, unit)) return GL_FALSE; /* Get first image here, since intelObj->firstLevel will get set in * the intel_finalize_mipmap_tree() call above. */ firstImage = tObj->Image[0][intelObj->firstLevel]; drm_intel_bo_reference(intelObj->mt->region->buffer); i915->state.tex_buffer[unit] = intelObj->mt->region->buffer; i915->state.tex_offset[unit] = 0; /* Always the origin of the miptree */ format = translate_texture_format(firstImage->TexFormat, firstImage->InternalFormat, tObj->DepthMode); pitch = intelObj->mt->region->pitch * intelObj->mt->cpp; state[I915_TEXREG_MS3] = (((firstImage->Height - 1) << MS3_HEIGHT_SHIFT) | ((firstImage->Width - 1) << MS3_WIDTH_SHIFT) | format); if (intelObj->mt->region->tiling != I915_TILING_NONE) { state[I915_TEXREG_MS3] |= MS3_TILED_SURFACE; if (intelObj->mt->region->tiling == I915_TILING_Y) state[I915_TEXREG_MS3] |= MS3_TILE_WALK; } /* We get one field with fraction bits for the maximum addressable * (lowest resolution) LOD. Use it to cover both MAX_LEVEL and * MAX_LOD. */ maxlod = MIN2(tObj->MaxLod, tObj->_MaxLevel - tObj->BaseLevel); state[I915_TEXREG_MS4] = ((((pitch / 4) - 1) << MS4_PITCH_SHIFT) | MS4_CUBE_FACE_ENA_MASK | (U_FIXED(CLAMP(maxlod, 0.0, 11.0), 2) << MS4_MAX_LOD_SHIFT) | ((firstImage->Depth - 1) << MS4_VOLUME_DEPTH_SHIFT)); { GLuint minFilt, mipFilt, magFilt; switch (tObj->MinFilter) { case GL_NEAREST: minFilt = FILTER_NEAREST; mipFilt = MIPFILTER_NONE; break; case GL_LINEAR: minFilt = FILTER_LINEAR; mipFilt = MIPFILTER_NONE; break; case GL_NEAREST_MIPMAP_NEAREST: minFilt = FILTER_NEAREST; mipFilt = MIPFILTER_NEAREST; break; case GL_LINEAR_MIPMAP_NEAREST: minFilt = FILTER_LINEAR; mipFilt = MIPFILTER_NEAREST; break; case GL_NEAREST_MIPMAP_LINEAR: minFilt = FILTER_NEAREST; mipFilt = MIPFILTER_LINEAR; break; case GL_LINEAR_MIPMAP_LINEAR: minFilt = FILTER_LINEAR; mipFilt = MIPFILTER_LINEAR; break; default: return GL_FALSE; } if (tObj->MaxAnisotropy > 1.0) { minFilt = FILTER_ANISOTROPIC; magFilt = FILTER_ANISOTROPIC; if (tObj->MaxAnisotropy > 2.0) aniso = SS2_MAX_ANISO_4; else aniso = SS2_MAX_ANISO_2; } else { switch (tObj->MagFilter) { case GL_NEAREST: magFilt = FILTER_NEAREST; break; case GL_LINEAR: magFilt = FILTER_LINEAR; break; default: return GL_FALSE; } } lodbias = (int) ((tUnit->LodBias + tObj->LodBias) * 16.0); if (lodbias < -256) lodbias = -256; if (lodbias > 255) lodbias = 255; state[I915_TEXREG_SS2] = ((lodbias << SS2_LOD_BIAS_SHIFT) & SS2_LOD_BIAS_MASK); /* YUV conversion: */ if (firstImage->TexFormat == MESA_FORMAT_YCBCR || firstImage->TexFormat == MESA_FORMAT_YCBCR_REV) state[I915_TEXREG_SS2] |= SS2_COLORSPACE_CONVERSION; /* Shadow: */ if (tObj->CompareMode == GL_COMPARE_R_TO_TEXTURE_ARB && tObj->Target != GL_TEXTURE_3D) { if (tObj->Target == GL_TEXTURE_1D) return GL_FALSE; state[I915_TEXREG_SS2] |= (SS2_SHADOW_ENABLE | intel_translate_shadow_compare_func(tObj->CompareFunc)); minFilt = FILTER_4X4_FLAT; magFilt = FILTER_4X4_FLAT; } state[I915_TEXREG_SS2] |= ((minFilt << SS2_MIN_FILTER_SHIFT) | (mipFilt << SS2_MIP_FILTER_SHIFT) | (magFilt << SS2_MAG_FILTER_SHIFT) | aniso); } { GLenum ws = tObj->WrapS; GLenum wt = tObj->WrapT; GLenum wr = tObj->WrapR; float minlod; /* We program 1D textures as 2D textures, so the 2D texcoord could * result in sampling border values if we don't set the T wrap to * repeat. */ if (tObj->Target == GL_TEXTURE_1D) wt = GL_REPEAT; /* 3D textures don't seem to respect the border color. * Fallback if there's ever a danger that they might refer to * it. * * Effectively this means fallback on 3D clamp or * clamp_to_border. */ if (tObj->Target == GL_TEXTURE_3D && (tObj->MinFilter != GL_NEAREST || tObj->MagFilter != GL_NEAREST) && (ws == GL_CLAMP || wt == GL_CLAMP || wr == GL_CLAMP || ws == GL_CLAMP_TO_BORDER || wt == GL_CLAMP_TO_BORDER || wr == GL_CLAMP_TO_BORDER)) return GL_FALSE; /* Only support TEXCOORDMODE_CLAMP_EDGE and TEXCOORDMODE_CUBE (not * used) when using cube map texture coordinates */ if (tObj->Target == GL_TEXTURE_CUBE_MAP_ARB && (((ws != GL_CLAMP) && (ws != GL_CLAMP_TO_EDGE)) || ((wt != GL_CLAMP) && (wt != GL_CLAMP_TO_EDGE)))) return GL_FALSE; state[I915_TEXREG_SS3] = ss3; /* SS3_NORMALIZED_COORDS */ state[I915_TEXREG_SS3] |= ((translate_wrap_mode(ws) << SS3_TCX_ADDR_MODE_SHIFT) | (translate_wrap_mode(wt) << SS3_TCY_ADDR_MODE_SHIFT) | (translate_wrap_mode(wr) << SS3_TCZ_ADDR_MODE_SHIFT)); minlod = MIN2(tObj->MinLod, tObj->_MaxLevel - tObj->BaseLevel); state[I915_TEXREG_SS3] |= (unit << SS3_TEXTUREMAP_INDEX_SHIFT); state[I915_TEXREG_SS3] |= (U_FIXED(CLAMP(minlod, 0.0, 11.0), 4) << SS3_MIN_LOD_SHIFT); } /* convert border color from float to ubyte */ CLAMPED_FLOAT_TO_UBYTE(border[0], tObj->BorderColor.f[0]); CLAMPED_FLOAT_TO_UBYTE(border[1], tObj->BorderColor.f[1]); CLAMPED_FLOAT_TO_UBYTE(border[2], tObj->BorderColor.f[2]); CLAMPED_FLOAT_TO_UBYTE(border[3], tObj->BorderColor.f[3]); if (firstImage->_BaseFormat == GL_DEPTH_COMPONENT) { /* GL specs that border color for depth textures is taken from the * R channel, while the hardware uses A. Spam R into all the channels * for safety. */ state[I915_TEXREG_SS4] = PACK_COLOR_8888(border[0], border[0], border[0], border[0]); } else { state[I915_TEXREG_SS4] = PACK_COLOR_8888(border[3], border[0], border[1], border[2]); } I915_ACTIVESTATE(i915, I915_UPLOAD_TEX(unit), GL_TRUE); /* memcmp was already disabled, but definitely won't work as the * region might now change and that wouldn't be detected: */ I915_STATECHANGE(i915, I915_UPLOAD_TEX(unit)); #if 0 DBG(TEXTURE, "state[I915_TEXREG_SS2] = 0x%x\n", state[I915_TEXREG_SS2]); DBG(TEXTURE, "state[I915_TEXREG_SS3] = 0x%x\n", state[I915_TEXREG_SS3]); DBG(TEXTURE, "state[I915_TEXREG_SS4] = 0x%x\n", state[I915_TEXREG_SS4]); DBG(TEXTURE, "state[I915_TEXREG_MS2] = 0x%x\n", state[I915_TEXREG_MS2]); DBG(TEXTURE, "state[I915_TEXREG_MS3] = 0x%x\n", state[I915_TEXREG_MS3]); DBG(TEXTURE, "state[I915_TEXREG_MS4] = 0x%x\n", state[I915_TEXREG_MS4]); #endif return GL_TRUE; }
/* Recalculate all state from scratch. Perhaps not the most * efficient, but this has gotten complex enough that we need * something which is understandable and reliable. */ static bool i915_update_tex_unit(struct intel_context *intel, GLuint unit, GLuint ss3) { struct gl_context *ctx = &intel->ctx; struct i915_context *i915 = i915_context(ctx); struct gl_texture_unit *tUnit = &ctx->Texture.Unit[unit]; struct gl_texture_object *tObj = tUnit->_Current; struct intel_texture_object *intelObj = intel_texture_object(tObj); struct gl_texture_image *firstImage; struct gl_sampler_object *sampler = _mesa_get_samplerobj(ctx, unit); GLuint *state = i915->state.Tex[unit], format, pitch; GLint lodbias, aniso = 0; GLubyte border[4]; GLfloat maxlod; memset(state, 0, sizeof(state)); /*We need to refcount these. */ if (i915->state.tex_buffer[unit] != NULL) { drm_intel_bo_unreference(i915->state.tex_buffer[unit]); i915->state.tex_buffer[unit] = NULL; } if (!intel_finalize_mipmap_tree(intel, unit)) return false; /* Get first image here, since intelObj->firstLevel will get set in * the intel_finalize_mipmap_tree() call above. */ firstImage = tObj->Image[0][tObj->BaseLevel]; drm_intel_bo_reference(intelObj->mt->region->bo); i915->state.tex_buffer[unit] = intelObj->mt->region->bo; i915->state.tex_offset[unit] = intelObj->mt->offset; format = translate_texture_format(firstImage->TexFormat, tObj->DepthMode); pitch = intelObj->mt->region->pitch * intelObj->mt->cpp; state[I915_TEXREG_MS3] = (((firstImage->Height - 1) << MS3_HEIGHT_SHIFT) | ((firstImage->Width - 1) << MS3_WIDTH_SHIFT) | format); if (intelObj->mt->region->tiling != I915_TILING_NONE) { state[I915_TEXREG_MS3] |= MS3_TILED_SURFACE; if (intelObj->mt->region->tiling == I915_TILING_Y) state[I915_TEXREG_MS3] |= MS3_TILE_WALK; } /* We get one field with fraction bits for the maximum addressable * (lowest resolution) LOD. Use it to cover both MAX_LEVEL and * MAX_LOD. */ maxlod = MIN2(sampler->MaxLod, tObj->_MaxLevel - tObj->BaseLevel); state[I915_TEXREG_MS4] = ((((pitch / 4) - 1) << MS4_PITCH_SHIFT) | MS4_CUBE_FACE_ENA_MASK | (U_FIXED(CLAMP(maxlod, 0.0, 11.0), 2) << MS4_MAX_LOD_SHIFT) | ((firstImage->Depth - 1) << MS4_VOLUME_DEPTH_SHIFT)); { GLuint minFilt, mipFilt, magFilt; switch (sampler->MinFilter) { case GL_NEAREST: minFilt = FILTER_NEAREST; mipFilt = MIPFILTER_NONE; break; case GL_LINEAR: minFilt = FILTER_LINEAR; mipFilt = MIPFILTER_NONE; break; case GL_NEAREST_MIPMAP_NEAREST: minFilt = FILTER_NEAREST; mipFilt = MIPFILTER_NEAREST; break; case GL_LINEAR_MIPMAP_NEAREST: minFilt = FILTER_LINEAR; mipFilt = MIPFILTER_NEAREST; break; case GL_NEAREST_MIPMAP_LINEAR: minFilt = FILTER_NEAREST; mipFilt = MIPFILTER_LINEAR; break; case GL_LINEAR_MIPMAP_LINEAR: minFilt = FILTER_LINEAR; mipFilt = MIPFILTER_LINEAR; break; default: return false; } if (sampler->MaxAnisotropy > 1.0) { minFilt = FILTER_ANISOTROPIC; magFilt = FILTER_ANISOTROPIC; if (sampler->MaxAnisotropy > 2.0) aniso = SS2_MAX_ANISO_4; else aniso = SS2_MAX_ANISO_2; } else { switch (sampler->MagFilter) { case GL_NEAREST: magFilt = FILTER_NEAREST; break; case GL_LINEAR: magFilt = FILTER_LINEAR; break; default: return false; } } lodbias = (int) ((tUnit->LodBias + sampler->LodBias) * 16.0); if (lodbias < -256) lodbias = -256; if (lodbias > 255) lodbias = 255; state[I915_TEXREG_SS2] = ((lodbias << SS2_LOD_BIAS_SHIFT) & SS2_LOD_BIAS_MASK); /* YUV conversion: */ if (firstImage->TexFormat == MESA_FORMAT_YCBCR || firstImage->TexFormat == MESA_FORMAT_YCBCR_REV) state[I915_TEXREG_SS2] |= SS2_COLORSPACE_CONVERSION; /* Shadow: */ if (sampler->CompareMode == GL_COMPARE_R_TO_TEXTURE_ARB && tObj->Target != GL_TEXTURE_3D) { if (tObj->Target == GL_TEXTURE_1D) return false; state[I915_TEXREG_SS2] |= (SS2_SHADOW_ENABLE | intel_translate_shadow_compare_func(sampler->CompareFunc)); minFilt = FILTER_4X4_FLAT; magFilt = FILTER_4X4_FLAT; } state[I915_TEXREG_SS2] |= ((minFilt << SS2_MIN_FILTER_SHIFT) | (mipFilt << SS2_MIP_FILTER_SHIFT) | (magFilt << SS2_MAG_FILTER_SHIFT) | aniso); } { GLenum ws = sampler->WrapS; GLenum wt = sampler->WrapT; GLenum wr = sampler->WrapR; float minlod; /* We program 1D textures as 2D textures, so the 2D texcoord could * result in sampling border values if we don't set the T wrap to * repeat. */ if (tObj->Target == GL_TEXTURE_1D) wt = GL_REPEAT; /* 3D textures don't seem to respect the border color. * Fallback if there's ever a danger that they might refer to * it. * * Effectively this means fallback on 3D clamp or * clamp_to_border. */ if (tObj->Target == GL_TEXTURE_3D && (sampler->MinFilter != GL_NEAREST || sampler->MagFilter != GL_NEAREST) && (ws == GL_CLAMP || wt == GL_CLAMP || wr == GL_CLAMP || ws == GL_CLAMP_TO_BORDER || wt == GL_CLAMP_TO_BORDER || wr == GL_CLAMP_TO_BORDER)) return false; /* Only support TEXCOORDMODE_CLAMP_EDGE and TEXCOORDMODE_CUBE (not * used) when using cube map texture coordinates */ if (tObj->Target == GL_TEXTURE_CUBE_MAP_ARB && (((ws != GL_CLAMP) && (ws != GL_CLAMP_TO_EDGE)) || ((wt != GL_CLAMP) && (wt != GL_CLAMP_TO_EDGE)))) return false; /* * According to 3DSTATE_MAP_STATE at page of 104 in Bspec * Vol3d 3D Instructions: * [DevGDG and DevAlv]: Must be a power of 2 for cube maps. * [DevLPT, DevCST and DevBLB]: If not a power of 2, cube maps * must have all faces enabled. * * But, as I tested on pineview(DevBLB derived), the rendering is * bad(you will find the color isn't samplered right in some * fragments). After checking, it seems that the texture layout is * wrong: making the width and height align of 4(although this * doesn't make much sense) will fix this issue and also broke some * others. Well, Bspec mentioned nothing about the layout alignment * and layout for NPOT cube map. I guess the Bspec just assume it's * a POT cube map. * * Thus, I guess we need do this for other platforms as well. */ if (tObj->Target == GL_TEXTURE_CUBE_MAP_ARB && !is_power_of_two(firstImage->Height)) return false; state[I915_TEXREG_SS3] = ss3; /* SS3_NORMALIZED_COORDS */ state[I915_TEXREG_SS3] |= ((translate_wrap_mode(ws) << SS3_TCX_ADDR_MODE_SHIFT) | (translate_wrap_mode(wt) << SS3_TCY_ADDR_MODE_SHIFT) | (translate_wrap_mode(wr) << SS3_TCZ_ADDR_MODE_SHIFT)); minlod = MIN2(sampler->MinLod, tObj->_MaxLevel - tObj->BaseLevel); state[I915_TEXREG_SS3] |= (unit << SS3_TEXTUREMAP_INDEX_SHIFT); state[I915_TEXREG_SS3] |= (U_FIXED(CLAMP(minlod, 0.0, 11.0), 4) << SS3_MIN_LOD_SHIFT); } /* convert border color from float to ubyte */ CLAMPED_FLOAT_TO_UBYTE(border[0], sampler->BorderColor.f[0]); CLAMPED_FLOAT_TO_UBYTE(border[1], sampler->BorderColor.f[1]); CLAMPED_FLOAT_TO_UBYTE(border[2], sampler->BorderColor.f[2]); CLAMPED_FLOAT_TO_UBYTE(border[3], sampler->BorderColor.f[3]); if (firstImage->_BaseFormat == GL_DEPTH_COMPONENT) { /* GL specs that border color for depth textures is taken from the * R channel, while the hardware uses A. Spam R into all the channels * for safety. */ state[I915_TEXREG_SS4] = PACK_COLOR_8888(border[0], border[0], border[0], border[0]); } else { state[I915_TEXREG_SS4] = PACK_COLOR_8888(border[3], border[0], border[1], border[2]); } I915_ACTIVESTATE(i915, I915_UPLOAD_TEX(unit), true); /* memcmp was already disabled, but definitely won't work as the * region might now change and that wouldn't be detected: */ I915_STATECHANGE(i915, I915_UPLOAD_TEX(unit)); #if 0 DBG(TEXTURE, "state[I915_TEXREG_SS2] = 0x%x\n", state[I915_TEXREG_SS2]); DBG(TEXTURE, "state[I915_TEXREG_SS3] = 0x%x\n", state[I915_TEXREG_SS3]); DBG(TEXTURE, "state[I915_TEXREG_SS4] = 0x%x\n", state[I915_TEXREG_SS4]); DBG(TEXTURE, "state[I915_TEXREG_MS2] = 0x%x\n", state[I915_TEXREG_MS2]); DBG(TEXTURE, "state[I915_TEXREG_MS3] = 0x%x\n", state[I915_TEXREG_MS3]); DBG(TEXTURE, "state[I915_TEXREG_MS4] = 0x%x\n", state[I915_TEXREG_MS4]); #endif return true; }
/* Push the state into the sarea and/or texture memory. */ static void i915_emit_state(struct intel_context *intel) { struct i915_context *i915 = i915_context(&intel->ctx); struct i915_hw_state *state = i915->current; int i; GLuint dirty; BATCH_LOCALS; /* We don't hold the lock at this point, so want to make sure that * there won't be a buffer wrap. * * It might be better to talk about explicit places where * scheduling is allowed, rather than assume that it is whenever a * batchbuffer fills up. */ intel_batchbuffer_require_space(intel->batch, get_state_size(state), 0); /* Do this here as we may have flushed the batchbuffer above, * causing more state to be dirty! */ dirty = get_dirty(state); if (INTEL_DEBUG & DEBUG_STATE) fprintf(stderr, "%s dirty: %x\n", __FUNCTION__, dirty); if (dirty & I915_UPLOAD_INVARIENT) { if (INTEL_DEBUG & DEBUG_STATE) fprintf(stderr, "I915_UPLOAD_INVARIENT:\n"); i915_emit_invarient_state(intel); } if (dirty & I915_UPLOAD_CTX) { if (INTEL_DEBUG & DEBUG_STATE) fprintf(stderr, "I915_UPLOAD_CTX:\n"); emit(intel, state->Ctx, sizeof(state->Ctx)); } if (dirty & I915_UPLOAD_BUFFERS) { if (INTEL_DEBUG & DEBUG_STATE) fprintf(stderr, "I915_UPLOAD_BUFFERS:\n"); BEGIN_BATCH(I915_DEST_SETUP_SIZE + 2, 0); OUT_BATCH(state->Buffer[I915_DESTREG_CBUFADDR0]); OUT_BATCH(state->Buffer[I915_DESTREG_CBUFADDR1]); OUT_RELOC(state->draw_region->buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE, DRM_BO_MASK_MEM | DRM_BO_FLAG_WRITE, state->draw_region->draw_offset); if (state->depth_region) { OUT_BATCH(state->Buffer[I915_DESTREG_DBUFADDR0]); OUT_BATCH(state->Buffer[I915_DESTREG_DBUFADDR1]); OUT_RELOC(state->depth_region->buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE, DRM_BO_MASK_MEM | DRM_BO_FLAG_WRITE, state->depth_region->draw_offset); } OUT_BATCH(state->Buffer[I915_DESTREG_DV0]); OUT_BATCH(state->Buffer[I915_DESTREG_DV1]); OUT_BATCH(state->Buffer[I915_DESTREG_SENABLE]); OUT_BATCH(state->Buffer[I915_DESTREG_SR0]); OUT_BATCH(state->Buffer[I915_DESTREG_SR1]); OUT_BATCH(state->Buffer[I915_DESTREG_SR2]); ADVANCE_BATCH(); } if (dirty & I915_UPLOAD_STIPPLE) { if (INTEL_DEBUG & DEBUG_STATE) fprintf(stderr, "I915_UPLOAD_STIPPLE:\n"); emit(intel, state->Stipple, sizeof(state->Stipple)); } if (dirty & I915_UPLOAD_FOG) { if (INTEL_DEBUG & DEBUG_STATE) fprintf(stderr, "I915_UPLOAD_FOG:\n"); emit(intel, state->Fog, sizeof(state->Fog)); } /* Combine all the dirty texture state into a single command to * avoid lockups on I915 hardware. */ if (dirty & I915_UPLOAD_TEX_ALL) { int nr = 0; for (i = 0; i < I915_TEX_UNITS; i++) if (dirty & I915_UPLOAD_TEX(i)) nr++; BEGIN_BATCH(2 + nr * 3, 0); OUT_BATCH(_3DSTATE_MAP_STATE | (3 * nr)); OUT_BATCH((dirty & I915_UPLOAD_TEX_ALL) >> I915_UPLOAD_TEX_0_SHIFT); for (i = 0; i < I915_TEX_UNITS; i++) if (dirty & I915_UPLOAD_TEX(i)) { if (state->tex_buffer[i]) { OUT_RELOC(state->tex_buffer[i], DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_READ, DRM_BO_MASK_MEM | DRM_BO_FLAG_READ, state->tex_offset[i]); } else { assert(i == 0); assert(state == &i915->meta); OUT_BATCH(0); } OUT_BATCH(state->Tex[i][I915_TEXREG_MS3]); OUT_BATCH(state->Tex[i][I915_TEXREG_MS4]); } ADVANCE_BATCH(); BEGIN_BATCH(2 + nr * 3, 0); OUT_BATCH(_3DSTATE_SAMPLER_STATE | (3 * nr)); OUT_BATCH((dirty & I915_UPLOAD_TEX_ALL) >> I915_UPLOAD_TEX_0_SHIFT); for (i = 0; i < I915_TEX_UNITS; i++) if (dirty & I915_UPLOAD_TEX(i)) { OUT_BATCH(state->Tex[i][I915_TEXREG_SS2]); OUT_BATCH(state->Tex[i][I915_TEXREG_SS3]); OUT_BATCH(state->Tex[i][I915_TEXREG_SS4]); } ADVANCE_BATCH(); }
/* Push the state into the sarea and/or texture memory. */ static void i915_emit_state(struct intel_context *intel) { struct i915_context *i915 = i915_context(&intel->ctx); struct i915_hw_state *state = i915->current; int i; int ret, count; GLuint dirty; GET_CURRENT_CONTEXT(ctx); BATCH_LOCALS; /* We don't hold the lock at this point, so want to make sure that * there won't be a buffer wrap between the state emits and the primitive * emit header. * * It might be better to talk about explicit places where * scheduling is allowed, rather than assume that it is whenever a * batchbuffer fills up. * * Set the space as LOOP_CLIPRECTS now, since that's what our primitives * will be emitted under. */ intel_batchbuffer_require_space(intel->batch, get_state_size(state) + 8, LOOP_CLIPRECTS); count = 0; again: dirty = get_dirty(state); ret = 0; if (dirty & I915_UPLOAD_BUFFERS) { ret |= dri_bufmgr_check_aperture_space(state->draw_region->buffer); if (state->depth_region) ret |= dri_bufmgr_check_aperture_space(state->depth_region->buffer); } if (dirty & I915_UPLOAD_TEX_ALL) { for (i = 0; i < I915_TEX_UNITS; i++) if (dirty & I915_UPLOAD_TEX(i)) { if (state->tex_buffer[i]) { ret |= dri_bufmgr_check_aperture_space(state->tex_buffer[i]); } } } if (ret) { if (count == 0) { count++; intel_batchbuffer_flush(intel->batch); goto again; } else { _mesa_error(ctx, GL_OUT_OF_MEMORY, "i915 emit state"); assert(0); } } /* work out list of buffers to emit */ /* Do this here as we may have flushed the batchbuffer above, * causing more state to be dirty! */ dirty = get_dirty(state); state->emitted |= dirty; assert(get_dirty(state) == 0); if (INTEL_DEBUG & DEBUG_STATE) fprintf(stderr, "%s dirty: %x\n", __FUNCTION__, dirty); if (dirty & I915_UPLOAD_INVARIENT) { if (INTEL_DEBUG & DEBUG_STATE) fprintf(stderr, "I915_UPLOAD_INVARIENT:\n"); i915_emit_invarient_state(intel); } if (dirty & I915_UPLOAD_CTX) { if (INTEL_DEBUG & DEBUG_STATE) fprintf(stderr, "I915_UPLOAD_CTX:\n"); emit(intel, state->Ctx, sizeof(state->Ctx)); } if (dirty & I915_UPLOAD_BUFFERS) { if (INTEL_DEBUG & DEBUG_STATE) fprintf(stderr, "I915_UPLOAD_BUFFERS:\n"); BEGIN_BATCH(I915_DEST_SETUP_SIZE + 2, IGNORE_CLIPRECTS); OUT_BATCH(state->Buffer[I915_DESTREG_CBUFADDR0]); OUT_BATCH(state->Buffer[I915_DESTREG_CBUFADDR1]); OUT_RELOC(state->draw_region->buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE, state->draw_region->draw_offset); if (state->depth_region) { OUT_BATCH(state->Buffer[I915_DESTREG_DBUFADDR0]); OUT_BATCH(state->Buffer[I915_DESTREG_DBUFADDR1]); OUT_RELOC(state->depth_region->buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE, state->depth_region->draw_offset); } OUT_BATCH(state->Buffer[I915_DESTREG_DV0]); OUT_BATCH(state->Buffer[I915_DESTREG_DV1]); OUT_BATCH(state->Buffer[I915_DESTREG_SENABLE]); OUT_BATCH(state->Buffer[I915_DESTREG_SR0]); OUT_BATCH(state->Buffer[I915_DESTREG_SR1]); OUT_BATCH(state->Buffer[I915_DESTREG_SR2]); ADVANCE_BATCH(); } if (dirty & I915_UPLOAD_STIPPLE) { if (INTEL_DEBUG & DEBUG_STATE) fprintf(stderr, "I915_UPLOAD_STIPPLE:\n"); emit(intel, state->Stipple, sizeof(state->Stipple)); } if (dirty & I915_UPLOAD_FOG) { if (INTEL_DEBUG & DEBUG_STATE) fprintf(stderr, "I915_UPLOAD_FOG:\n"); emit(intel, state->Fog, sizeof(state->Fog)); } /* Combine all the dirty texture state into a single command to * avoid lockups on I915 hardware. */ if (dirty & I915_UPLOAD_TEX_ALL) { int nr = 0; for (i = 0; i < I915_TEX_UNITS; i++) if (dirty & I915_UPLOAD_TEX(i)) nr++; BEGIN_BATCH(2 + nr * 3, IGNORE_CLIPRECTS); OUT_BATCH(_3DSTATE_MAP_STATE | (3 * nr)); OUT_BATCH((dirty & I915_UPLOAD_TEX_ALL) >> I915_UPLOAD_TEX_0_SHIFT); for (i = 0; i < I915_TEX_UNITS; i++) if (dirty & I915_UPLOAD_TEX(i)) { if (state->tex_buffer[i]) { OUT_RELOC(state->tex_buffer[i], DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_READ, state->tex_offset[i]); } else if (state == &i915->meta) { assert(i == 0); OUT_BATCH(0); } else { OUT_BATCH(state->tex_offset[i]); } OUT_BATCH(state->Tex[i][I915_TEXREG_MS3]); OUT_BATCH(state->Tex[i][I915_TEXREG_MS4]); } ADVANCE_BATCH(); BEGIN_BATCH(2 + nr * 3, IGNORE_CLIPRECTS); OUT_BATCH(_3DSTATE_SAMPLER_STATE | (3 * nr)); OUT_BATCH((dirty & I915_UPLOAD_TEX_ALL) >> I915_UPLOAD_TEX_0_SHIFT); for (i = 0; i < I915_TEX_UNITS; i++) if (dirty & I915_UPLOAD_TEX(i)) { OUT_BATCH(state->Tex[i][I915_TEXREG_SS2]); OUT_BATCH(state->Tex[i][I915_TEXREG_SS3]); OUT_BATCH(state->Tex[i][I915_TEXREG_SS4]); } ADVANCE_BATCH(); }