void _mesa_update_fetch_functions(struct gl_context *ctx, GLuint unit) { struct gl_texture_object *texObj = ctx->Texture.Unit[unit]._Current; struct gl_sampler_object *samp; GLuint face, i; GLuint dims; if (!texObj) return; samp = _mesa_get_samplerobj(ctx, unit); dims = _mesa_get_texture_dimensions(texObj->Target); for (face = 0; face < 6; face++) { for (i = 0; i < MAX_TEXTURE_LEVELS; i++) { if (texObj->Image[face][i]) { set_fetch_functions(samp, swrast_texture_image(texObj->Image[face][i]), dims); } } } }
static GLboolean update_single_texture(struct st_context *st, struct pipe_sampler_view **sampler_view, GLuint texUnit) { struct pipe_context *pipe = st->pipe; struct gl_context *ctx = st->ctx; const struct gl_sampler_object *samp; struct gl_texture_object *texObj; struct st_texture_object *stObj; enum pipe_format view_format; GLboolean retval; samp = _mesa_get_samplerobj(ctx, texUnit); texObj = ctx->Texture.Unit[texUnit]._Current; if (!texObj) { texObj = _mesa_get_fallback_texture(ctx, TEXTURE_2D_INDEX); samp = &texObj->Sampler; } stObj = st_texture_object(texObj); retval = st_finalize_texture(ctx, st->pipe, texObj); if (!retval) { /* out of mem */ return GL_FALSE; } /* Determine the format of the texture sampler view */ if (texObj->Target == GL_TEXTURE_BUFFER) { view_format = st_mesa_format_to_pipe_format(stObj->base._BufferObjectFormat); } else { view_format = stObj->pt->format; /* If sRGB decoding is off, use the linear format */ if (samp->sRGBDecode == GL_SKIP_DECODE_EXT) { view_format = util_format_linear(view_format); } } /* if sampler view has changed dereference it */ if (stObj->sampler_view) { if (check_sampler_swizzle(stObj->sampler_view, stObj->base._Swizzle, stObj->base.DepthMode) || (view_format != stObj->sampler_view->format) || stObj->base.BaseLevel != stObj->sampler_view->u.tex.first_level) { pipe_sampler_view_reference(&stObj->sampler_view, NULL); } } *sampler_view = st_get_texture_sampler_view_from_stobj(stObj, pipe, samp, view_format); return GL_TRUE; }
void brw_populate_sampler_prog_key_data(struct gl_context *ctx, const struct gl_program *prog, unsigned sampler_count, struct brw_sampler_prog_key_data *key) { struct brw_context *brw = brw_context(ctx); for (int s = 0; s < sampler_count; s++) { key->swizzles[s] = SWIZZLE_NOOP; if (!(prog->SamplersUsed & (1 << s))) continue; int unit_id = prog->SamplerUnits[s]; const struct gl_texture_unit *unit = &ctx->Texture.Unit[unit_id]; if (unit->_ReallyEnabled && unit->_Current->Target != GL_TEXTURE_BUFFER) { const struct gl_texture_object *t = unit->_Current; const struct gl_texture_image *img = t->Image[0][t->BaseLevel]; struct gl_sampler_object *sampler = _mesa_get_samplerobj(ctx, unit_id); const bool alpha_depth = t->DepthMode == GL_ALPHA && (img->_BaseFormat == GL_DEPTH_COMPONENT || img->_BaseFormat == GL_DEPTH_STENCIL); /* Haswell handles texture swizzling as surface format overrides * (except for GL_ALPHA); all other platforms need MOVs in the shader. */ if (!brw->is_haswell || alpha_depth) key->swizzles[s] = brw_get_texture_swizzle(ctx, t); if (img->InternalFormat == GL_YCBCR_MESA) { key->yuvtex_mask |= 1 << s; if (img->TexFormat == MESA_FORMAT_YCBCR) key->yuvtex_swap_mask |= 1 << s; } if (sampler->MinFilter != GL_NEAREST && sampler->MagFilter != GL_NEAREST) { if (sampler->WrapS == GL_CLAMP) key->gl_clamp_mask[0] |= 1 << s; if (sampler->WrapT == GL_CLAMP) key->gl_clamp_mask[1] |= 1 << s; if (sampler->WrapR == GL_CLAMP) key->gl_clamp_mask[2] |= 1 << s; } /* gather4's channel select for green from RG32F is broken; * requires a shader w/a on IVB; fixable with just SCS on HSW. */ if (brw->gen >= 7 && !brw->is_haswell && prog->UsesGather) { if (img->InternalFormat == GL_RG32F) key->gather_channel_quirk_mask |= 1 << s; } } } }
void r200TexUpdateParameters(struct gl_context *ctx, GLuint unit) { struct gl_sampler_object *samp = _mesa_get_samplerobj(ctx, unit); radeonTexObj* t = radeon_tex_obj(ctx->Texture.Unit[unit]._Current); r200SetTexMaxAnisotropy(t , samp->MaxAnisotropy); r200SetTexFilter(t, samp->MinFilter, samp->MagFilter); r200SetTexWrap(t, samp->WrapS, samp->WrapT, samp->WrapR); r200SetTexBorderColor(t, samp->BorderColor.f); }
/** * Fetch a texel. */ static void fetch_texel(struct gl_context * ctx, const GLfloat texcoord[4], GLfloat lambda, GLuint unit, GLfloat color[4]) { SWcontext *swrast = SWRAST_CONTEXT(ctx); /* XXX use a float-valued TextureSample routine here!!! */ swrast->TextureSample[unit](ctx, _mesa_get_samplerobj(ctx, unit), ctx->Texture.Unit[unit]._Current, 1, (const GLfloat(*)[4]) texcoord, &lambda, (GLfloat (*)[4]) color); }
void brw_populate_sampler_prog_key_data(struct gl_context *ctx, const struct gl_program *prog, struct brw_sampler_prog_key_data *key) { struct intel_context *intel = intel_context(ctx); for (int s = 0; s < MAX_SAMPLERS; s++) { key->swizzles[s] = SWIZZLE_NOOP; if (!(prog->SamplersUsed & (1 << s))) continue; int unit_id = prog->SamplerUnits[s]; const struct gl_texture_unit *unit = &ctx->Texture.Unit[unit_id]; if (unit->_ReallyEnabled && unit->_Current->Target != GL_TEXTURE_BUFFER) { const struct gl_texture_object *t = unit->_Current; const struct gl_texture_image *img = t->Image[0][t->BaseLevel]; struct gl_sampler_object *sampler = _mesa_get_samplerobj(ctx, unit_id); const bool alpha_depth = t->DepthMode == GL_ALPHA && (img->_BaseFormat == GL_DEPTH_COMPONENT || img->_BaseFormat == GL_DEPTH_STENCIL); /* Haswell handles texture swizzling as surface format overrides * (except for GL_ALPHA); all other platforms need MOVs in the shader. */ if (!intel->is_haswell || alpha_depth) key->swizzles[s] = brw_get_texture_swizzle(ctx, t); if (img->InternalFormat == GL_YCBCR_MESA) { key->yuvtex_mask |= 1 << s; if (img->TexFormat == MESA_FORMAT_YCBCR) key->yuvtex_swap_mask |= 1 << s; } if (sampler->MinFilter != GL_NEAREST && sampler->MagFilter != GL_NEAREST) { if (sampler->WrapS == GL_CLAMP) key->gl_clamp_mask[0] |= 1 << s; if (sampler->WrapT == GL_CLAMP) key->gl_clamp_mask[1] |= 1 << s; if (sampler->WrapR == GL_CLAMP) key->gl_clamp_mask[2] |= 1 << s; } } } }
static GLboolean update_single_texture(struct st_context *st, struct pipe_sampler_view **sampler_view, GLuint texUnit, unsigned glsl_version) { struct gl_context *ctx = st->ctx; const struct gl_sampler_object *samp; struct gl_texture_object *texObj; struct st_texture_object *stObj; enum pipe_format view_format; GLboolean retval; samp = _mesa_get_samplerobj(ctx, texUnit); texObj = ctx->Texture.Unit[texUnit]._Current; if (!texObj) { texObj = _mesa_get_fallback_texture(ctx, TEXTURE_2D_INDEX); samp = &texObj->Sampler; } stObj = st_texture_object(texObj); retval = st_finalize_texture(ctx, st->pipe, texObj); if (!retval) { /* out of mem */ return GL_FALSE; } /* Determine the format of the texture sampler view */ if (texObj->Target == GL_TEXTURE_BUFFER) { view_format = st_mesa_format_to_pipe_format(st, stObj->base._BufferObjectFormat); } else { view_format = stObj->surface_based ? stObj->surface_format : stObj->pt->format; /* If sRGB decoding is off, use the linear format */ if (samp->sRGBDecode == GL_SKIP_DECODE_EXT) { view_format = util_format_linear(view_format); } } *sampler_view = st_get_texture_sampler_view_from_stobj(st, stObj, view_format, glsl_version); return GL_TRUE; }
static GLboolean update_single_texture(struct st_context *st, struct pipe_sampler_view **sampler_view, GLuint texUnit, unsigned glsl_version) { struct gl_context *ctx = st->ctx; const struct gl_sampler_object *samp; struct gl_texture_object *texObj; struct st_texture_object *stObj; GLboolean retval; samp = _mesa_get_samplerobj(ctx, texUnit); texObj = ctx->Texture.Unit[texUnit]._Current; if (!texObj) { texObj = _mesa_get_fallback_texture(ctx, TEXTURE_2D_INDEX); samp = &texObj->Sampler; } stObj = st_texture_object(texObj); retval = st_finalize_texture(ctx, st->pipe, texObj); if (!retval) { /* out of mem */ return GL_FALSE; } /* Check a few pieces of state outside the texture object to see if we * need to force revalidation. */ if (stObj->prev_glsl_version != glsl_version || stObj->prev_sRGBDecode != samp->sRGBDecode) { st_texture_release_all_sampler_views(st, stObj); stObj->prev_glsl_version = glsl_version; stObj->prev_sRGBDecode = samp->sRGBDecode; } if (texObj->TargetIndex == TEXTURE_EXTERNAL_INDEX && stObj->pt->screen->resource_changed) stObj->pt->screen->resource_changed(stObj->pt->screen, stObj->pt); *sampler_view = st_get_texture_sampler_view_from_stobj(st, stObj, samp, glsl_version); return GL_TRUE; }
void _swrast_update_texture_samplers(struct gl_context *ctx) { SWcontext *swrast = SWRAST_CONTEXT(ctx); GLuint u; if (!swrast) return; /* pipe hack */ for (u = 0; u < ARRAY_SIZE(swrast->TextureSample); u++) { struct gl_texture_object *tObj = ctx->Texture.Unit[u]._Current; /* Note: If tObj is NULL, the sample function will be a simple * function that just returns opaque black (0,0,0,1). */ _mesa_update_fetch_functions(ctx, u); swrast->TextureSample[u] = _swrast_choose_texture_sample_func(ctx, tObj, _mesa_get_samplerobj(ctx, u)); } }
/** * Fetch a texel with the given partial derivatives to compute a level * of detail in the mipmap. * Called via machine->FetchTexelDeriv() * \param lodBias the lod bias which may be specified by a TXB instruction, * otherwise zero. */ static void fetch_texel_deriv( struct gl_context *ctx, const GLfloat texcoord[4], const GLfloat texdx[4], const GLfloat texdy[4], GLfloat lodBias, GLuint unit, GLfloat color[4] ) { SWcontext *swrast = SWRAST_CONTEXT(ctx); const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; const struct gl_texture_object *texObj = texUnit->_Current; if (texObj) { const struct gl_texture_image *texImg = texObj->Image[0][texObj->BaseLevel]; const struct swrast_texture_image *swImg = swrast_texture_image_const(texImg); const struct gl_sampler_object *samp = _mesa_get_samplerobj(ctx, unit); const GLfloat texW = (GLfloat) swImg->WidthScale; const GLfloat texH = (GLfloat) swImg->HeightScale; GLfloat lambda; GLfloat rgba[4]; lambda = _swrast_compute_lambda(texdx[0], texdy[0], /* ds/dx, ds/dy */ texdx[1], texdy[1], /* dt/dx, dt/dy */ texdx[3], texdy[3], /* dq/dx, dq/dy */ texW, texH, texcoord[0], texcoord[1], texcoord[3], 1.0F / texcoord[3]); lambda += lodBias + texUnit->LodBias + samp->LodBias; lambda = CLAMP(lambda, samp->MinLod, samp->MaxLod); swrast->TextureSample[unit](ctx, samp, ctx->Texture.Unit[unit]._Current, 1, (const GLfloat (*)[4]) texcoord, &lambda, &rgba); swizzle_texel(rgba, color, texObj->_Swizzle); } else { ASSIGN_4V(color, 0.0F, 0.0F, 0.0F, 1.0F); } }
/** * Fetch a texel with given lod. * Called via machine->FetchTexelLod() */ static void fetch_texel_lod( struct gl_context *ctx, const GLfloat texcoord[4], GLfloat lambda, GLuint unit, GLfloat color[4] ) { const struct gl_texture_object *texObj = ctx->Texture.Unit[unit]._Current; if (texObj) { SWcontext *swrast = SWRAST_CONTEXT(ctx); GLfloat rgba[4]; const struct gl_sampler_object *samp = _mesa_get_samplerobj(ctx, unit); lambda = CLAMP(lambda, samp->MinLod, samp->MaxLod); swrast->TextureSample[unit](ctx, samp, ctx->Texture.Unit[unit]._Current, 1, (const GLfloat (*)[4]) texcoord, &lambda, &rgba); swizzle_texel(rgba, color, texObj->_Swizzle); } else { ASSIGN_4V(color, 0.0F, 0.0F, 0.0F, 1.0F); } }
/** * Get a pipe_sampler_view object from a texture unit. */ void st_update_single_texture(struct st_context *st, struct pipe_sampler_view **sampler_view, GLuint texUnit, bool glsl130_or_later, bool ignore_srgb_decode) { struct gl_context *ctx = st->ctx; const struct gl_sampler_object *samp; struct gl_texture_object *texObj; struct st_texture_object *stObj; samp = _mesa_get_samplerobj(ctx, texUnit); texObj = ctx->Texture.Unit[texUnit]._Current; assert(texObj); stObj = st_texture_object(texObj); if (unlikely(texObj->Target == GL_TEXTURE_BUFFER)) { *sampler_view = st_get_buffer_sampler_view_from_stobj(st, stObj); return; } if (!st_finalize_texture(ctx, st->pipe, texObj, 0) || !stObj->pt) { /* out of mem */ *sampler_view = NULL; return; } if (texObj->TargetIndex == TEXTURE_EXTERNAL_INDEX && stObj->pt->screen->resource_changed) stObj->pt->screen->resource_changed(stObj->pt->screen, stObj->pt); *sampler_view = st_get_texture_sampler_view_from_stobj(st, stObj, samp, glsl130_or_later, ignore_srgb_decode); }
void brw_populate_sampler_prog_key_data(struct gl_context *ctx, const struct gl_program *prog, unsigned sampler_count, struct brw_sampler_prog_key_data *key) { struct brw_context *brw = brw_context(ctx); for (int s = 0; s < sampler_count; s++) { key->swizzles[s] = SWIZZLE_NOOP; if (!(prog->SamplersUsed & (1 << s))) continue; int unit_id = prog->SamplerUnits[s]; const struct gl_texture_unit *unit = &ctx->Texture.Unit[unit_id]; if (unit->_Current && unit->_Current->Target != GL_TEXTURE_BUFFER) { const struct gl_texture_object *t = unit->_Current; const struct gl_texture_image *img = t->Image[0][t->BaseLevel]; struct gl_sampler_object *sampler = _mesa_get_samplerobj(ctx, unit_id); const bool alpha_depth = t->DepthMode == GL_ALPHA && (img->_BaseFormat == GL_DEPTH_COMPONENT || img->_BaseFormat == GL_DEPTH_STENCIL); /* Haswell handles texture swizzling as surface format overrides * (except for GL_ALPHA); all other platforms need MOVs in the shader. */ if (alpha_depth || (brw->gen < 8 && !brw->is_haswell)) key->swizzles[s] = brw_get_texture_swizzle(ctx, t); if (brw->gen < 8 && sampler->MinFilter != GL_NEAREST && sampler->MagFilter != GL_NEAREST) { if (sampler->WrapS == GL_CLAMP) key->gl_clamp_mask[0] |= 1 << s; if (sampler->WrapT == GL_CLAMP) key->gl_clamp_mask[1] |= 1 << s; if (sampler->WrapR == GL_CLAMP) key->gl_clamp_mask[2] |= 1 << s; } /* gather4's channel select for green from RG32F is broken; requires * a shader w/a on IVB; fixable with just SCS on HSW. */ if (brw->gen == 7 && !brw->is_haswell && prog->UsesGather) { if (img->InternalFormat == GL_RG32F) key->gather_channel_quirk_mask |= 1 << s; } /* Gen6's gather4 is broken for UINT/SINT; we treat them as * UNORM/FLOAT instead and fix it in the shader. */ if (brw->gen == 6 && prog->UsesGather) { key->gen6_gather_wa[s] = gen6_gather_workaround(img->InternalFormat); } /* If this is a multisample sampler, and uses the CMS MSAA layout, * then we need to emit slightly different code to first sample the * MCS surface. */ struct intel_texture_object *intel_tex = intel_texture_object((struct gl_texture_object *)t); if (brw->gen >= 7 && intel_tex->mt->msaa_layout == INTEL_MSAA_LAYOUT_CMS) { key->compressed_multisample_layout_mask |= 1 << s; if (intel_tex->mt->num_samples >= 16) { assert(brw->gen >= 9); key->msaa_16 |= 1 << s; } } } } }
/** * Apply texture mapping to a span of fragments. */ void _swrast_texture_span( struct gl_context *ctx, SWspan *span ) { SWcontext *swrast = SWRAST_CONTEXT(ctx); float4_array primary_rgba; GLuint unit; if (!swrast->TexelBuffer) { #ifdef _OPENMP const GLint maxThreads = omp_get_max_threads(); #else const GLint maxThreads = 1; #endif /* TexelBuffer is also global and normally shared by all SWspan * instances; when running with multiple threads, create one per * thread. */ swrast->TexelBuffer = malloc(ctx->Const.FragmentProgram.MaxTextureImageUnits * maxThreads * SWRAST_MAX_WIDTH * 4 * sizeof(GLfloat)); if (!swrast->TexelBuffer) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "texture_combine"); return; } } primary_rgba = malloc(span->end * 4 * sizeof(GLfloat)); if (!primary_rgba) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "texture_span"); return; } ASSERT(span->end <= SWRAST_MAX_WIDTH); /* * Save copy of the incoming fragment colors (the GL_PRIMARY_COLOR) */ if (swrast->_TextureCombinePrimary) { GLuint i; for (i = 0; i < span->end; i++) { primary_rgba[i][RCOMP] = CHAN_TO_FLOAT(span->array->rgba[i][RCOMP]); primary_rgba[i][GCOMP] = CHAN_TO_FLOAT(span->array->rgba[i][GCOMP]); primary_rgba[i][BCOMP] = CHAN_TO_FLOAT(span->array->rgba[i][BCOMP]); primary_rgba[i][ACOMP] = CHAN_TO_FLOAT(span->array->rgba[i][ACOMP]); } } /* First must sample all bump maps */ for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) { const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; if (texUnit->_ReallyEnabled && texUnit->_CurrentCombine->ModeRGB == GL_BUMP_ENVMAP_ATI) { const GLfloat (*texcoords)[4] = (const GLfloat (*)[4]) span->array->attribs[VARYING_SLOT_TEX0 + unit]; float4_array targetcoords = span->array->attribs[VARYING_SLOT_TEX0 + ctx->Texture.Unit[unit].BumpTarget - GL_TEXTURE0]; const struct gl_sampler_object *samp = _mesa_get_samplerobj(ctx, unit); GLfloat *lambda = span->array->lambda[unit]; float4_array texels = get_texel_array(swrast, unit); GLuint i; GLfloat rotMatrix00 = ctx->Texture.Unit[unit].RotMatrix[0]; GLfloat rotMatrix01 = ctx->Texture.Unit[unit].RotMatrix[1]; GLfloat rotMatrix10 = ctx->Texture.Unit[unit].RotMatrix[2]; GLfloat rotMatrix11 = ctx->Texture.Unit[unit].RotMatrix[3]; /* adjust texture lod (lambda) */ if (span->arrayMask & SPAN_LAMBDA) { if (texUnit->LodBias + samp->LodBias != 0.0F) { /* apply LOD bias, but don't clamp yet */ const GLfloat bias = CLAMP(texUnit->LodBias + samp->LodBias, -ctx->Const.MaxTextureLodBias, ctx->Const.MaxTextureLodBias); GLuint i; for (i = 0; i < span->end; i++) { lambda[i] += bias; } } if (samp->MinLod != -1000.0 || samp->MaxLod != 1000.0) { /* apply LOD clamping to lambda */ const GLfloat min = samp->MinLod; const GLfloat max = samp->MaxLod; GLuint i; for (i = 0; i < span->end; i++) { GLfloat l = lambda[i]; lambda[i] = CLAMP(l, min, max); } } } /* Sample the texture (span->end = number of fragments) */ swrast->TextureSample[unit]( ctx, samp, ctx->Texture.Unit[unit]._Current, span->end, texcoords, lambda, texels ); /* manipulate the span values of the bump target not sure this can work correctly even ignoring the problem that channel is unsigned */ for (i = 0; i < span->end; i++) { targetcoords[i][0] += (texels[i][0] * rotMatrix00 + texels[i][1] * rotMatrix01) / targetcoords[i][3]; targetcoords[i][1] += (texels[i][0] * rotMatrix10 + texels[i][1] * rotMatrix11) / targetcoords[i][3]; } } } /* * Must do all texture sampling before combining in order to * accomodate GL_ARB_texture_env_crossbar. */ for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) { const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; if (texUnit->_ReallyEnabled && texUnit->_CurrentCombine->ModeRGB != GL_BUMP_ENVMAP_ATI) { const GLfloat (*texcoords)[4] = (const GLfloat (*)[4]) span->array->attribs[VARYING_SLOT_TEX0 + unit]; const struct gl_texture_object *curObj = texUnit->_Current; const struct gl_sampler_object *samp = _mesa_get_samplerobj(ctx, unit); GLfloat *lambda = span->array->lambda[unit]; float4_array texels = get_texel_array(swrast, unit); /* adjust texture lod (lambda) */ if (span->arrayMask & SPAN_LAMBDA) { if (texUnit->LodBias + samp->LodBias != 0.0F) { /* apply LOD bias, but don't clamp yet */ const GLfloat bias = CLAMP(texUnit->LodBias + samp->LodBias, -ctx->Const.MaxTextureLodBias, ctx->Const.MaxTextureLodBias); GLuint i; for (i = 0; i < span->end; i++) { lambda[i] += bias; } } if (samp->MinLod != -1000.0 || samp->MaxLod != 1000.0) { /* apply LOD clamping to lambda */ const GLfloat min = samp->MinLod; const GLfloat max = samp->MaxLod; GLuint i; for (i = 0; i < span->end; i++) { GLfloat l = lambda[i]; lambda[i] = CLAMP(l, min, max); } } } else if (samp->MaxAnisotropy > 1.0 && samp->MinFilter == GL_LINEAR_MIPMAP_LINEAR) { /* sample_lambda_2d_aniso is beeing used as texture_sample_func, * it requires the current SWspan *span as an additional parameter. * In order to keep the same function signature, the unused lambda * parameter will be modified to actually contain the SWspan pointer. * This is a Hack. To make it right, the texture_sample_func * signature and all implementing functions need to be modified. */ /* "hide" SWspan struct; cast to (GLfloat *) to suppress warning */ lambda = (GLfloat *)span; } /* Sample the texture (span->end = number of fragments) */ swrast->TextureSample[unit]( ctx, samp, ctx->Texture.Unit[unit]._Current, span->end, texcoords, lambda, texels ); /* GL_EXT_texture_swizzle */ if (curObj->_Swizzle != SWIZZLE_NOOP) { swizzle_texels(curObj->_Swizzle, span->end, texels); } } } /* * OK, now apply the texture (aka texture combine/blend). * We modify the span->color.rgba values. */ for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) { if (ctx->Texture.Unit[unit]._ReallyEnabled) texture_combine(ctx, unit, primary_rgba, swrast->TexelBuffer, span); } free(primary_rgba); }
GLuint intel_finalize_mipmap_tree(struct intel_context *intel, GLuint unit) { struct gl_context *ctx = &intel->ctx; struct gl_texture_object *tObj = intel->ctx.Texture.Unit[unit]._Current; struct intel_texture_object *intelObj = intel_texture_object(tObj); struct gl_sampler_object *sampler = _mesa_get_samplerobj(ctx, unit); GLuint face, i; GLuint nr_faces = 0; struct intel_texture_image *firstImage; int width, height, depth; /* TBOs require no validation -- they always just point to their BO. */ if (tObj->Target == GL_TEXTURE_BUFFER) return true; /* We know/require this is true by now: */ assert(intelObj->base._BaseComplete); /* What levels must the tree include at a minimum? */ intel_update_max_level(intelObj, sampler); if (intelObj->mt && intelObj->mt->first_level != tObj->BaseLevel) intelObj->needs_validate = true; if (!intelObj->needs_validate) return true; firstImage = intel_texture_image(tObj->Image[0][tObj->BaseLevel]); /* Check tree can hold all active levels. Check tree matches * target, imageFormat, etc. * * For pre-gen4, we have to match first_level == tObj->BaseLevel, * because we don't have the control that gen4 does to make min/mag * determination happen at a nonzero (hardware) baselevel. Because * of that, we just always relayout on baselevel change. */ if (intelObj->mt && (!intel_miptree_match_image(intelObj->mt, &firstImage->base.Base) || intelObj->mt->first_level != tObj->BaseLevel || intelObj->mt->last_level < intelObj->_MaxLevel)) { intel_miptree_release(&intelObj->mt); } /* May need to create a new tree: */ if (!intelObj->mt) { intel_miptree_get_dimensions_for_image(&firstImage->base.Base, &width, &height, &depth); perf_debug("Creating new %s %dx%dx%d %d..%d miptree to handle finalized " "texture miptree.\n", _mesa_get_format_name(firstImage->base.Base.TexFormat), width, height, depth, tObj->BaseLevel, intelObj->_MaxLevel); intelObj->mt = intel_miptree_create(intel, intelObj->base.Target, firstImage->base.Base.TexFormat, tObj->BaseLevel, intelObj->_MaxLevel, width, height, depth, true, 0 /* num_samples */, false /* force_y_tiling */); if (!intelObj->mt) return false; } /* Pull in any images not in the object's tree: */ nr_faces = _mesa_num_tex_faces(intelObj->base.Target); for (face = 0; face < nr_faces; face++) { for (i = tObj->BaseLevel; i <= intelObj->_MaxLevel; i++) { struct intel_texture_image *intelImage = intel_texture_image(intelObj->base.Image[face][i]); /* skip too small size mipmap */ if (intelImage == NULL) break; if (intelObj->mt != intelImage->mt) { intel_miptree_copy_teximage(intel, intelImage, intelObj->mt, false /* invalidate */); } /* After we're done, we'd better agree that our layout is * appropriate, or we'll end up hitting this function again on the * next draw */ assert(intel_miptree_match_image(intelObj->mt, &intelImage->base.Base)); } } intelObj->needs_validate = false; return true; }
GLuint intel_finalize_mipmap_tree(struct intel_context *intel, GLuint unit) { struct gl_context *ctx = &intel->ctx; struct gl_texture_object *tObj = intel->ctx.Texture.Unit[unit]._Current; struct intel_texture_object *intelObj = intel_texture_object(tObj); struct gl_sampler_object *sampler = _mesa_get_samplerobj(ctx, unit); GLuint face, i; GLuint nr_faces = 0; struct intel_texture_image *firstImage; /* We know/require this is true by now: */ assert(intelObj->base._Complete); /* What levels must the tree include at a minimum? */ intel_update_max_level(intel, intelObj, sampler); firstImage = intel_texture_image(tObj->Image[0][tObj->BaseLevel]); /* Fallback case: */ if (firstImage->base.Border) { if (intelObj->mt) { intel_miptree_release(intel, &intelObj->mt); } return GL_FALSE; } /* Check tree can hold all active levels. Check tree matches * target, imageFormat, etc. * * For pre-gen4, we have to match first_level == tObj->BaseLevel, * because we don't have the control that gen4 does to make min/mag * determination happen at a nonzero (hardware) baselevel. Because * of that, we just always relayout on baselevel change. */ if (intelObj->mt && (intelObj->mt->target != intelObj->base.Target || intelObj->mt->format != firstImage->base.TexFormat || intelObj->mt->first_level != tObj->BaseLevel || intelObj->mt->last_level < intelObj->_MaxLevel || intelObj->mt->width0 != firstImage->base.Width || intelObj->mt->height0 != firstImage->base.Height || intelObj->mt->depth0 != firstImage->base.Depth)) { intel_miptree_release(intel, &intelObj->mt); } /* May need to create a new tree: */ if (!intelObj->mt) { intelObj->mt = intel_miptree_create(intel, intelObj->base.Target, firstImage->base.TexFormat, tObj->BaseLevel, intelObj->_MaxLevel, firstImage->base.Width, firstImage->base.Height, firstImage->base.Depth, GL_TRUE); if (!intelObj->mt) return GL_FALSE; } /* Pull in any images not in the object's tree: */ nr_faces = (intelObj->base.Target == GL_TEXTURE_CUBE_MAP) ? 6 : 1; for (face = 0; face < nr_faces; face++) { for (i = tObj->BaseLevel; i <= intelObj->_MaxLevel; i++) { struct intel_texture_image *intelImage = intel_texture_image(intelObj->base.Image[face][i]); /* skip too small size mipmap */ if (intelImage == NULL) break; /* Need to import images in main memory or held in other trees. * If it's a render target, then its data isn't needed to be in * the object tree (otherwise we'd be FBO incomplete), and we need * to keep track of the image's MT as needing to be pulled in still, * or we'll lose the rendering that's done to it. */ if (intelObj->mt != intelImage->mt && !intelImage->used_as_render_target) { copy_image_data_to_tree(intel, intelObj, intelImage); } } } return GL_TRUE; }
/** * At rendering-from-a-texture time, make sure that the texture object has a * miptree that can hold the entire texture based on * BaseLevel/MaxLevel/filtering, and copy in any texture images that are * stored in other miptrees. */ GLuint intel_finalize_mipmap_tree(struct brw_context *brw, GLuint unit) { struct gl_context *ctx = &brw->ctx; struct gl_texture_object *tObj = ctx->Texture.Unit[unit]._Current; struct intel_texture_object *intelObj = intel_texture_object(tObj); struct gl_sampler_object *sampler = _mesa_get_samplerobj(ctx, unit); GLuint face, i; GLuint nr_faces = 0; struct intel_texture_image *firstImage; int width, height, depth; /* TBOs require no validation -- they always just point to their BO. */ if (tObj->Target == GL_TEXTURE_BUFFER) return true; /* We know that this is true by now, and if it wasn't, we might have * mismatched level sizes and the copies would fail. */ assert(intelObj->base._BaseComplete); intel_update_max_level(intelObj, sampler); /* What levels does this validated texture image require? */ int validate_first_level = tObj->BaseLevel; int validate_last_level = intelObj->_MaxLevel; /* Skip the loop over images in the common case of no images having * changed. But if the GL_BASE_LEVEL or GL_MAX_LEVEL change to something we * haven't looked at, then we do need to look at those new images. */ if (!intelObj->needs_validate && validate_first_level >= intelObj->validated_first_level && validate_last_level <= intelObj->validated_last_level) { return true; } /* Immutable textures should not get this far -- they should have been * created in a validated state, and nothing can invalidate them. */ assert(!tObj->Immutable); firstImage = intel_texture_image(tObj->Image[0][tObj->BaseLevel]); /* Check tree can hold all active levels. Check tree matches * target, imageFormat, etc. * * For pre-gen4, we have to match first_level == tObj->BaseLevel, * because we don't have the control that gen4 does to make min/mag * determination happen at a nonzero (hardware) baselevel. Because * of that, we just always relayout on baselevel change. */ if (intelObj->mt && (!intel_miptree_match_image(intelObj->mt, &firstImage->base.Base) || validate_first_level < intelObj->mt->first_level || validate_last_level > intelObj->mt->last_level)) { intel_miptree_release(&intelObj->mt); } /* May need to create a new tree: */ if (!intelObj->mt) { intel_miptree_get_dimensions_for_image(&firstImage->base.Base, &width, &height, &depth); perf_debug("Creating new %s %dx%dx%d %d-level miptree to handle " "finalized texture miptree.\n", _mesa_get_format_name(firstImage->base.Base.TexFormat), width, height, depth, validate_last_level + 1); intelObj->mt = intel_miptree_create(brw, intelObj->base.Target, firstImage->base.Base.TexFormat, 0, /* first_level */ validate_last_level, width, height, depth, true, 0 /* num_samples */, INTEL_MIPTREE_TILING_ANY); if (!intelObj->mt) return false; } /* Pull in any images not in the object's tree: */ nr_faces = _mesa_num_tex_faces(intelObj->base.Target); for (face = 0; face < nr_faces; face++) { for (i = validate_first_level; i <= validate_last_level; i++) { struct intel_texture_image *intelImage = intel_texture_image(intelObj->base.Image[face][i]); /* skip too small size mipmap */ if (intelImage == NULL) break; if (intelObj->mt != intelImage->mt) { intel_miptree_copy_teximage(brw, intelImage, intelObj->mt, false /* invalidate */); } /* After we're done, we'd better agree that our layout is * appropriate, or we'll end up hitting this function again on the * next draw */ assert(intel_miptree_match_image(intelObj->mt, &intelImage->base.Base)); } } intelObj->validated_first_level = validate_first_level; intelObj->validated_last_level = validate_last_level; intelObj->_Format = intelObj->mt->format; intelObj->needs_validate = false; return 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; }
/** * Sets the sampler state for a single unit. */ static void gen7_update_sampler_state(struct brw_context *brw, int unit, int ss_index, struct gen7_sampler_state *sampler, uint32_t *sdc_offset) { struct gl_context *ctx = &brw->ctx; struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; struct gl_texture_object *texObj = texUnit->_Current; struct gl_sampler_object *gl_sampler = _mesa_get_samplerobj(ctx, unit); bool using_nearest = false; /* These don't use samplers at all. */ if (texObj->Target == GL_TEXTURE_BUFFER) return; switch (gl_sampler->MinFilter) { case GL_NEAREST: sampler->ss0.min_filter = BRW_MAPFILTER_NEAREST; sampler->ss0.mip_filter = BRW_MIPFILTER_NONE; using_nearest = true; break; case GL_LINEAR: sampler->ss0.min_filter = BRW_MAPFILTER_LINEAR; sampler->ss0.mip_filter = BRW_MIPFILTER_NONE; break; case GL_NEAREST_MIPMAP_NEAREST: sampler->ss0.min_filter = BRW_MAPFILTER_NEAREST; sampler->ss0.mip_filter = BRW_MIPFILTER_NEAREST; break; case GL_LINEAR_MIPMAP_NEAREST: sampler->ss0.min_filter = BRW_MAPFILTER_LINEAR; sampler->ss0.mip_filter = BRW_MIPFILTER_NEAREST; break; case GL_NEAREST_MIPMAP_LINEAR: sampler->ss0.min_filter = BRW_MAPFILTER_NEAREST; sampler->ss0.mip_filter = BRW_MIPFILTER_LINEAR; break; case GL_LINEAR_MIPMAP_LINEAR: sampler->ss0.min_filter = BRW_MAPFILTER_LINEAR; sampler->ss0.mip_filter = BRW_MIPFILTER_LINEAR; break; default: break; } /* Set Anisotropy: */ if (gl_sampler->MaxAnisotropy > 1.0) { sampler->ss0.min_filter = BRW_MAPFILTER_ANISOTROPIC; sampler->ss0.mag_filter = BRW_MAPFILTER_ANISOTROPIC; sampler->ss0.aniso_algorithm = 1; if (gl_sampler->MaxAnisotropy > 2.0) { sampler->ss3.max_aniso = MIN2((gl_sampler->MaxAnisotropy - 2) / 2, BRW_ANISORATIO_16); } } else { switch (gl_sampler->MagFilter) { case GL_NEAREST: sampler->ss0.mag_filter = BRW_MAPFILTER_NEAREST; using_nearest = true; break; case GL_LINEAR: sampler->ss0.mag_filter = BRW_MAPFILTER_LINEAR; break; default: break; } } sampler->ss3.r_wrap_mode = translate_wrap_mode(gl_sampler->WrapR, using_nearest); sampler->ss3.s_wrap_mode = translate_wrap_mode(gl_sampler->WrapS, using_nearest); sampler->ss3.t_wrap_mode = translate_wrap_mode(gl_sampler->WrapT, using_nearest); /* Cube-maps on 965 and later must use the same wrap mode for all 3 * coordinate dimensions. Futher, only CUBE and CLAMP are valid. */ if (texObj->Target == GL_TEXTURE_CUBE_MAP || texObj->Target == GL_TEXTURE_CUBE_MAP_ARRAY) { if ((ctx->Texture.CubeMapSeamless || gl_sampler->CubeMapSeamless) && (gl_sampler->MinFilter != GL_NEAREST || gl_sampler->MagFilter != GL_NEAREST)) { sampler->ss3.r_wrap_mode = BRW_TEXCOORDMODE_CUBE; sampler->ss3.s_wrap_mode = BRW_TEXCOORDMODE_CUBE; sampler->ss3.t_wrap_mode = BRW_TEXCOORDMODE_CUBE; } else { sampler->ss3.r_wrap_mode = BRW_TEXCOORDMODE_CLAMP; sampler->ss3.s_wrap_mode = BRW_TEXCOORDMODE_CLAMP; sampler->ss3.t_wrap_mode = BRW_TEXCOORDMODE_CLAMP; } } else if (texObj->Target == GL_TEXTURE_1D) { /* There's a bug in 1D texture sampling - it actually pays * attention to the wrap_t value, though it should not. * Override the wrap_t value here to GL_REPEAT to keep * any nonexistent border pixels from floating in. */ sampler->ss3.t_wrap_mode = BRW_TEXCOORDMODE_WRAP; } /* Set shadow function: */ if (gl_sampler->CompareMode == GL_COMPARE_R_TO_TEXTURE_ARB) { /* Shadowing is "enabled" by emitting a particular sampler * message (sample_c). So need to recompile WM program when * shadow comparison is enabled on each/any texture unit. */ sampler->ss1.shadow_function = intel_translate_shadow_compare_func(gl_sampler->CompareFunc); } /* Set LOD bias: */ sampler->ss0.lod_bias = S_FIXED(CLAMP(texUnit->LodBias + gl_sampler->LodBias, -16, 15), 8); sampler->ss0.lod_preclamp = 1; /* OpenGL mode */ sampler->ss0.default_color_mode = 0; /* OpenGL/DX10 mode */ sampler->ss0.base_level = U_FIXED(0, 1); sampler->ss1.max_lod = U_FIXED(CLAMP(gl_sampler->MaxLod, 0, 13), 8); sampler->ss1.min_lod = U_FIXED(CLAMP(gl_sampler->MinLod, 0, 13), 8); /* The sampler can handle non-normalized texture rectangle coordinates * natively */ if (texObj->Target == GL_TEXTURE_RECTANGLE) { sampler->ss3.non_normalized_coord = 1; } upload_default_color(brw, gl_sampler, unit, sdc_offset); sampler->ss2.default_color_pointer = *sdc_offset >> 5; if (sampler->ss0.min_filter != BRW_MAPFILTER_NEAREST) sampler->ss3.address_round |= BRW_ADDRESS_ROUNDING_ENABLE_U_MIN | BRW_ADDRESS_ROUNDING_ENABLE_V_MIN | BRW_ADDRESS_ROUNDING_ENABLE_R_MIN; if (sampler->ss0.mag_filter != BRW_MAPFILTER_NEAREST) sampler->ss3.address_round |= BRW_ADDRESS_ROUNDING_ENABLE_U_MAG | BRW_ADDRESS_ROUNDING_ENABLE_V_MAG | BRW_ADDRESS_ROUNDING_ENABLE_R_MAG; }
static void convert_sampler(struct st_context *st, struct pipe_sampler_state *sampler, GLuint texUnit) { struct gl_texture_object *texobj; struct gl_context *ctx = st->ctx; struct gl_sampler_object *msamp; texobj = ctx->Texture.Unit[texUnit]._Current; if (!texobj) { texobj = _mesa_get_fallback_texture(ctx, TEXTURE_2D_INDEX); } msamp = _mesa_get_samplerobj(ctx, texUnit); memset(sampler, 0, sizeof(*sampler)); sampler->wrap_s = gl_wrap_xlate(msamp->WrapS); sampler->wrap_t = gl_wrap_xlate(msamp->WrapT); sampler->wrap_r = gl_wrap_xlate(msamp->WrapR); sampler->min_img_filter = gl_filter_to_img_filter(msamp->MinFilter); sampler->min_mip_filter = gl_filter_to_mip_filter(msamp->MinFilter); sampler->mag_img_filter = gl_filter_to_img_filter(msamp->MagFilter); if (texobj->Target != GL_TEXTURE_RECTANGLE_ARB) sampler->normalized_coords = 1; sampler->lod_bias = ctx->Texture.Unit[texUnit].LodBias + msamp->LodBias; sampler->min_lod = CLAMP(msamp->MinLod, 0.0f, (GLfloat) texobj->MaxLevel - texobj->BaseLevel); sampler->max_lod = MIN2((GLfloat) texobj->MaxLevel - texobj->BaseLevel, msamp->MaxLod); if (sampler->max_lod < sampler->min_lod) { /* The GL spec doesn't seem to specify what to do in this case. * Swap the values. */ float tmp = sampler->max_lod; sampler->max_lod = sampler->min_lod; sampler->min_lod = tmp; assert(sampler->min_lod <= sampler->max_lod); } if (msamp->BorderColor.ui[0] || msamp->BorderColor.ui[1] || msamp->BorderColor.ui[2] || msamp->BorderColor.ui[3]) { struct st_texture_object *stobj = st_texture_object(texobj); struct gl_texture_image *teximg; GLboolean is_integer = GL_FALSE; union pipe_color_union border_color; teximg = texobj->Image[0][texobj->BaseLevel]; if (teximg) { is_integer = _mesa_is_enum_format_integer(teximg->InternalFormat); } if (st->apply_texture_swizzle_to_border_color && stobj->sampler_view) { const unsigned char swz[4] = { stobj->sampler_view->swizzle_r, stobj->sampler_view->swizzle_g, stobj->sampler_view->swizzle_b, stobj->sampler_view->swizzle_a, }; st_translate_color(&msamp->BorderColor, &border_color, teximg ? teximg->_BaseFormat : GL_RGBA, is_integer); util_format_apply_color_swizzle(&sampler->border_color, &border_color, swz, is_integer); } else { st_translate_color(&msamp->BorderColor, &sampler->border_color, teximg ? teximg->_BaseFormat : GL_RGBA, is_integer); } } sampler->max_anisotropy = (msamp->MaxAnisotropy == 1.0 ? 0 : (GLuint) msamp->MaxAnisotropy); /* only care about ARB_shadow, not SGI shadow */ if (msamp->CompareMode == GL_COMPARE_R_TO_TEXTURE) { sampler->compare_mode = PIPE_TEX_COMPARE_R_TO_TEXTURE; sampler->compare_func = st_compare_func_to_pipe(msamp->CompareFunc); } sampler->seamless_cube_map = ctx->Texture.CubeMapSeamless || msamp->CubeMapSeamless; }
/** * Sets the sampler state for a single unit. */ static void gen7_update_sampler_state(struct brw_context *brw, int unit, struct gen7_sampler_state *sampler) { struct intel_context *intel = &brw->intel; struct gl_context *ctx = &intel->ctx; struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; struct gl_texture_object *texObj = texUnit->_Current; struct gl_sampler_object *gl_sampler = _mesa_get_samplerobj(ctx, unit); bool using_nearest = false; switch (gl_sampler->MinFilter) { case GL_NEAREST: sampler->ss0.min_filter = BRW_MAPFILTER_NEAREST; sampler->ss0.mip_filter = BRW_MIPFILTER_NONE; using_nearest = true; break; case GL_LINEAR: sampler->ss0.min_filter = BRW_MAPFILTER_LINEAR; sampler->ss0.mip_filter = BRW_MIPFILTER_NONE; break; case GL_NEAREST_MIPMAP_NEAREST: sampler->ss0.min_filter = BRW_MAPFILTER_NEAREST; sampler->ss0.mip_filter = BRW_MIPFILTER_NEAREST; break; case GL_LINEAR_MIPMAP_NEAREST: sampler->ss0.min_filter = BRW_MAPFILTER_LINEAR; sampler->ss0.mip_filter = BRW_MIPFILTER_NEAREST; break; case GL_NEAREST_MIPMAP_LINEAR: sampler->ss0.min_filter = BRW_MAPFILTER_NEAREST; sampler->ss0.mip_filter = BRW_MIPFILTER_LINEAR; break; case GL_LINEAR_MIPMAP_LINEAR: sampler->ss0.min_filter = BRW_MAPFILTER_LINEAR; sampler->ss0.mip_filter = BRW_MIPFILTER_LINEAR; break; default: break; } /* Set Anisotropy: */ if (gl_sampler->MaxAnisotropy > 1.0) { sampler->ss0.min_filter = BRW_MAPFILTER_ANISOTROPIC; sampler->ss0.mag_filter = BRW_MAPFILTER_ANISOTROPIC; if (gl_sampler->MaxAnisotropy > 2.0) { sampler->ss3.max_aniso = MIN2((gl_sampler->MaxAnisotropy - 2) / 2, BRW_ANISORATIO_16); } } else { switch (gl_sampler->MagFilter) { case GL_NEAREST: sampler->ss0.mag_filter = BRW_MAPFILTER_NEAREST; using_nearest = true; break; case GL_LINEAR: sampler->ss0.mag_filter = BRW_MAPFILTER_LINEAR; break; default: break; } } sampler->ss3.r_wrap_mode = translate_wrap_mode(gl_sampler->WrapR, using_nearest); sampler->ss3.s_wrap_mode = translate_wrap_mode(gl_sampler->WrapS, using_nearest); sampler->ss3.t_wrap_mode = translate_wrap_mode(gl_sampler->WrapT, using_nearest); /* Cube-maps on 965 and later must use the same wrap mode for all 3 * coordinate dimensions. Futher, only CUBE and CLAMP are valid. */ if (texObj->Target == GL_TEXTURE_CUBE_MAP) { if (ctx->Texture.CubeMapSeamless && (gl_sampler->MinFilter != GL_NEAREST || gl_sampler->MagFilter != GL_NEAREST)) { sampler->ss3.r_wrap_mode = BRW_TEXCOORDMODE_CUBE; sampler->ss3.s_wrap_mode = BRW_TEXCOORDMODE_CUBE; sampler->ss3.t_wrap_mode = BRW_TEXCOORDMODE_CUBE; } else { sampler->ss3.r_wrap_mode = BRW_TEXCOORDMODE_CLAMP; sampler->ss3.s_wrap_mode = BRW_TEXCOORDMODE_CLAMP; sampler->ss3.t_wrap_mode = BRW_TEXCOORDMODE_CLAMP; } } else if (texObj->Target == GL_TEXTURE_1D) { /* There's a bug in 1D texture sampling - it actually pays * attention to the wrap_t value, though it should not. * Override the wrap_t value here to GL_REPEAT to keep * any nonexistent border pixels from floating in. */ sampler->ss3.t_wrap_mode = BRW_TEXCOORDMODE_WRAP; } /* Set shadow function: */ if (gl_sampler->CompareMode == GL_COMPARE_R_TO_TEXTURE_ARB) { /* Shadowing is "enabled" by emitting a particular sampler * message (sample_c). So need to recompile WM program when * shadow comparison is enabled on each/any texture unit. */ sampler->ss1.shadow_function = intel_translate_shadow_compare_func(gl_sampler->CompareFunc); } /* Set LOD bias: */ sampler->ss0.lod_bias = S_FIXED(CLAMP(texUnit->LodBias + gl_sampler->LodBias, -16, 15), 8); sampler->ss0.lod_preclamp = 1; /* OpenGL mode */ sampler->ss0.default_color_mode = 0; /* OpenGL/DX10 mode */ /* Set BaseMipLevel, MaxLOD, MinLOD: * * XXX: I don't think that using firstLevel, lastLevel works, * because we always setup the surface state as if firstLevel == * level zero. Probably have to subtract firstLevel from each of * these: */ sampler->ss0.base_level = U_FIXED(0, 1); sampler->ss1.max_lod = U_FIXED(CLAMP(gl_sampler->MaxLod, 0, 13), 8); sampler->ss1.min_lod = U_FIXED(CLAMP(gl_sampler->MinLod, 0, 13), 8); upload_default_color(brw, gl_sampler, unit); sampler->ss2.default_color_pointer = brw->wm.sdc_offset[unit] >> 5; }
GLuint intel_finalize_mipmap_tree(struct intel_context *intel, GLuint unit) { struct gl_context *ctx = &intel->ctx; struct gl_texture_object *tObj = intel->ctx.Texture.Unit[unit]._Current; struct intel_texture_object *intelObj = intel_texture_object(tObj); struct gl_sampler_object *sampler = _mesa_get_samplerobj(ctx, unit); GLuint face, i; GLuint nr_faces = 0; struct intel_texture_image *firstImage; int width, height, depth; /* TBOs require no validation -- they always just point to their BO. */ if (tObj->Target == GL_TEXTURE_BUFFER) return true; /* We know/require this is true by now: */ assert(intelObj->base._BaseComplete); /* What levels must the tree include at a minimum? */ intel_update_max_level(intelObj, sampler); firstImage = intel_texture_image(tObj->Image[0][tObj->BaseLevel]); /* Check tree can hold all active levels. Check tree matches * target, imageFormat, etc. * * For pre-gen4, we have to match first_level == tObj->BaseLevel, * because we don't have the control that gen4 does to make min/mag * determination happen at a nonzero (hardware) baselevel. Because * of that, we just always relayout on baselevel change. */ if (intelObj->mt && (!intel_miptree_match_image(intelObj->mt, &firstImage->base.Base) || intelObj->mt->first_level != tObj->BaseLevel || intelObj->mt->last_level < intelObj->_MaxLevel)) { intel_miptree_release(&intelObj->mt); } /* May need to create a new tree: */ if (!intelObj->mt) { intel_miptree_get_dimensions_for_image(&firstImage->base.Base, &width, &height, &depth); intelObj->mt = intel_miptree_create(intel, intelObj->base.Target, firstImage->base.Base.TexFormat, tObj->BaseLevel, intelObj->_MaxLevel, width, height, depth, true, 0 /* num_samples */, false /* msaa_is_interleaved */); if (!intelObj->mt) return false; } /* Pull in any images not in the object's tree: */ nr_faces = (intelObj->base.Target == GL_TEXTURE_CUBE_MAP) ? 6 : 1; for (face = 0; face < nr_faces; face++) { for (i = tObj->BaseLevel; i <= intelObj->_MaxLevel; i++) { struct intel_texture_image *intelImage = intel_texture_image(intelObj->base.Image[face][i]); /* skip too small size mipmap */ if (intelImage == NULL) break; if (intelObj->mt != intelImage->mt) { intel_miptree_copy_teximage(intel, intelImage, intelObj->mt); } } } return 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 i830_update_tex_unit(struct intel_context *intel, GLuint unit, GLuint ss3) { struct gl_context *ctx = &intel->ctx; struct i830_context *i830 = i830_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 = i830->state.Tex[unit], format, pitch; GLint lodbias; GLubyte border[4]; GLuint dst_x, dst_y; memset(state, 0, sizeof(*state)); /*We need to refcount these. */ if (i830->state.tex_buffer[unit] != NULL) { drm_intel_bo_unreference(i830->state.tex_buffer[unit]); i830->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]; intel_miptree_get_image_offset(intelObj->mt, tObj->BaseLevel, 0, &dst_x, &dst_y); drm_intel_bo_reference(intelObj->mt->region->bo); i830->state.tex_buffer[unit] = intelObj->mt->region->bo; pitch = intelObj->mt->region->pitch; /* XXX: This calculation is probably broken for tiled images with * a non-page-aligned offset. */ i830->state.tex_offset[unit] = dst_x * intelObj->mt->cpp + dst_y * pitch; format = translate_texture_format(firstImage->TexFormat); state[I830_TEXREG_TM0LI] = (_3DSTATE_LOAD_STATE_IMMEDIATE_2 | (LOAD_TEXTURE_MAP0 << unit) | 4); state[I830_TEXREG_TM0S1] = (((firstImage->Height - 1) << TM0S1_HEIGHT_SHIFT) | ((firstImage->Width - 1) << TM0S1_WIDTH_SHIFT) | format); if (intelObj->mt->region->tiling != I915_TILING_NONE) { state[I830_TEXREG_TM0S1] |= TM0S1_TILED_SURFACE; if (intelObj->mt->region->tiling == I915_TILING_Y) state[I830_TEXREG_TM0S1] |= TM0S1_TILE_WALK; } state[I830_TEXREG_TM0S2] = ((((pitch / 4) - 1) << TM0S2_PITCH_SHIFT) | TM0S2_CUBE_FACE_ENA_MASK); { if (tObj->Target == GL_TEXTURE_CUBE_MAP) state[I830_TEXREG_CUBE] = (_3DSTATE_MAP_CUBE | MAP_UNIT(unit) | CUBE_NEGX_ENABLE | CUBE_POSX_ENABLE | CUBE_NEGY_ENABLE | CUBE_POSY_ENABLE | CUBE_NEGZ_ENABLE | CUBE_POSZ_ENABLE); else state[I830_TEXREG_CUBE] = (_3DSTATE_MAP_CUBE | MAP_UNIT(unit)); } { GLuint minFilt, mipFilt, magFilt; float maxlod; uint32_t minlod_fixed, maxlod_fixed; 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; } 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 < -64) lodbias = -64; if (lodbias > 63) lodbias = 63; state[I830_TEXREG_TM0S3] = ((lodbias << TM0S3_LOD_BIAS_SHIFT) & TM0S3_LOD_BIAS_MASK); #if 0 /* YUV conversion: */ if (firstImage->TexFormat->MesaFormat == MESA_FORMAT_YCBCR || firstImage->TexFormat->MesaFormat == MESA_FORMAT_YCBCR_REV) state[I830_TEXREG_TM0S3] |= SS2_COLORSPACE_CONVERSION; #endif /* We get one field with fraction bits for the maximum * addressable (smallest resolution) LOD. Use it to cover both * MAX_LEVEL and MAX_LOD. */ minlod_fixed = U_FIXED(CLAMP(sampler->MinLod, 0.0, 11), 4); maxlod = MIN2(sampler->MaxLod, tObj->_MaxLevel - tObj->BaseLevel); if (intel->intelScreen->deviceID == PCI_CHIP_I855_GM || intel->intelScreen->deviceID == PCI_CHIP_I865_G) { maxlod_fixed = U_FIXED(CLAMP(maxlod, 0.0, 11.75), 2); maxlod_fixed = MAX2(maxlod_fixed, (minlod_fixed + 3) >> 2); state[I830_TEXREG_TM0S3] |= maxlod_fixed << TM0S3_MIN_MIP_SHIFT; state[I830_TEXREG_TM0S2] |= TM0S2_LOD_PRECLAMP; } else {
void nv20_emit_tex_obj(struct gl_context *ctx, int emit) { const int i = emit - NOUVEAU_STATE_TEX_OBJ0; struct nouveau_pushbuf *push = context_push(ctx); const int bo_flags = NOUVEAU_BO_RD | NOUVEAU_BO_GART | NOUVEAU_BO_VRAM; struct gl_texture_object *t; struct nouveau_surface *s; struct gl_texture_image *ti; const struct gl_sampler_object *sa; uint32_t tx_format, tx_filter, tx_wrap, tx_enable; PUSH_RESET(push, BUFCTX_TEX(i)); if (!ctx->Texture.Unit[i]._ReallyEnabled) { BEGIN_NV04(push, NV20_3D(TEX_ENABLE(i)), 1); PUSH_DATA (push, 0); context_dirty(ctx, TEX_SHADER); return; } t = ctx->Texture.Unit[i]._Current; s = &to_nouveau_texture(t)->surfaces[t->BaseLevel]; ti = t->Image[0][t->BaseLevel]; sa = _mesa_get_samplerobj(ctx, i); if (!nouveau_texture_validate(ctx, t)) return; /* Recompute the texturing registers. */ tx_format = ti->DepthLog2 << 28 | ti->HeightLog2 << 24 | ti->WidthLog2 << 20 | NV20_3D_TEX_FORMAT_DIMS_2D | NV20_3D_TEX_FORMAT_NO_BORDER | 1 << 16; tx_wrap = nvgl_wrap_mode(sa->WrapR) << 16 | nvgl_wrap_mode(sa->WrapT) << 8 | nvgl_wrap_mode(sa->WrapS) << 0; tx_filter = nvgl_filter_mode(sa->MagFilter) << 24 | nvgl_filter_mode(sa->MinFilter) << 16 | 2 << 12; tx_enable = NV20_3D_TEX_ENABLE_ENABLE | log2i(sa->MaxAnisotropy) << 4; if (t->Target == GL_TEXTURE_RECTANGLE) { BEGIN_NV04(push, NV20_3D(TEX_NPOT_PITCH(i)), 1); PUSH_DATA (push, s->pitch << 16); BEGIN_NV04(push, NV20_3D(TEX_NPOT_SIZE(i)), 1); PUSH_DATA (push, s->width << 16 | s->height); tx_format |= get_tex_format_rect(ti); } else { tx_format |= get_tex_format_pot(ti); } if (sa->MinFilter != GL_NEAREST && sa->MinFilter != GL_LINEAR) { int lod_min = sa->MinLod; int lod_max = MIN2(sa->MaxLod, t->_MaxLambda); int lod_bias = sa->LodBias + ctx->Texture.Unit[i].LodBias; lod_max = CLAMP(lod_max, 0, 15); lod_min = CLAMP(lod_min, 0, 15); lod_bias = CLAMP(lod_bias, 0, 15); tx_format |= NV20_3D_TEX_FORMAT_MIPMAP; tx_filter |= lod_bias << 8; tx_enable |= lod_min << 26 | lod_max << 14; } /* Write it to the hardware. */ BEGIN_NV04(push, NV20_3D(TEX_FORMAT(i)), 1); PUSH_MTHD (push, NV20_3D(TEX_FORMAT(i)), BUFCTX_TEX(i), s->bo, tx_format, bo_flags | NOUVEAU_BO_OR, NV20_3D_TEX_FORMAT_DMA0, NV20_3D_TEX_FORMAT_DMA1); BEGIN_NV04(push, NV20_3D(TEX_OFFSET(i)), 1); PUSH_MTHDl(push, NV20_3D(TEX_OFFSET(i)), BUFCTX_TEX(i), s->bo, s->offset, bo_flags); BEGIN_NV04(push, NV20_3D(TEX_WRAP(i)), 1); PUSH_DATA (push, tx_wrap); BEGIN_NV04(push, NV20_3D(TEX_FILTER(i)), 1); PUSH_DATA (push, tx_filter); BEGIN_NV04(push, NV20_3D(TEX_ENABLE(i)), 1); PUSH_DATA (push, tx_enable); context_dirty(ctx, TEX_SHADER); }
static void convert_sampler(struct st_context *st, struct pipe_sampler_state *sampler, GLuint texUnit) { const struct gl_texture_object *texobj; struct gl_context *ctx = st->ctx; const struct gl_sampler_object *msamp; GLenum texBaseFormat; texobj = ctx->Texture.Unit[texUnit]._Current; if (!texobj) { texobj = _mesa_get_fallback_texture(ctx, TEXTURE_2D_INDEX); msamp = &texobj->Sampler; } else { msamp = _mesa_get_samplerobj(ctx, texUnit); } texBaseFormat = _mesa_texture_base_format(texobj); memset(sampler, 0, sizeof(*sampler)); sampler->wrap_s = gl_wrap_xlate(msamp->WrapS); sampler->wrap_t = gl_wrap_xlate(msamp->WrapT); sampler->wrap_r = gl_wrap_xlate(msamp->WrapR); sampler->min_img_filter = gl_filter_to_img_filter(msamp->MinFilter); sampler->min_mip_filter = gl_filter_to_mip_filter(msamp->MinFilter); sampler->mag_img_filter = gl_filter_to_img_filter(msamp->MagFilter); if (texobj->Target != GL_TEXTURE_RECTANGLE_ARB) sampler->normalized_coords = 1; sampler->lod_bias = ctx->Texture.Unit[texUnit].LodBias + msamp->LodBias; sampler->min_lod = MAX2(msamp->MinLod, 0.0f); sampler->max_lod = msamp->MaxLod; if (sampler->max_lod < sampler->min_lod) { /* The GL spec doesn't seem to specify what to do in this case. * Swap the values. */ float tmp = sampler->max_lod; sampler->max_lod = sampler->min_lod; sampler->min_lod = tmp; assert(sampler->min_lod <= sampler->max_lod); } /* For non-black borders... */ if (msamp->BorderColor.ui[0] || msamp->BorderColor.ui[1] || msamp->BorderColor.ui[2] || msamp->BorderColor.ui[3]) { const struct st_texture_object *stobj = st_texture_object_const(texobj); const GLboolean is_integer = texobj->_IsIntegerFormat; const struct pipe_sampler_view *sv = NULL; union pipe_color_union border_color; GLuint i; /* Just search for the first used view. We can do this because the swizzle is per-texture, not per context. */ /* XXX: clean that up to not use the sampler view at all */ for (i = 0; i < stobj->num_sampler_views; ++i) { if (stobj->sampler_views[i]) { sv = stobj->sampler_views[i]; break; } } if (st->apply_texture_swizzle_to_border_color && sv) { const unsigned char swz[4] = { sv->swizzle_r, sv->swizzle_g, sv->swizzle_b, sv->swizzle_a, }; st_translate_color(&msamp->BorderColor, &border_color, texBaseFormat, is_integer); util_format_apply_color_swizzle(&sampler->border_color, &border_color, swz, is_integer); } else { st_translate_color(&msamp->BorderColor, &sampler->border_color, texBaseFormat, is_integer); } } sampler->max_anisotropy = (msamp->MaxAnisotropy == 1.0 ? 0 : (GLuint) msamp->MaxAnisotropy); /* If sampling a depth texture and using shadow comparison */ if ((texBaseFormat == GL_DEPTH_COMPONENT || texBaseFormat == GL_DEPTH_STENCIL) && msamp->CompareMode == GL_COMPARE_R_TO_TEXTURE) { sampler->compare_mode = PIPE_TEX_COMPARE_R_TO_TEXTURE; sampler->compare_func = st_compare_func_to_pipe(msamp->CompareFunc); } sampler->seamless_cube_map = ctx->Texture.CubeMapSeamless || msamp->CubeMapSeamless; }
void brw_populate_sampler_prog_key_data(struct gl_context *ctx, const struct gl_program *prog, struct brw_sampler_prog_key_data *key) { struct brw_context *brw = brw_context(ctx); const struct gen_device_info *devinfo = &brw->screen->devinfo; GLbitfield mask = prog->SamplersUsed; while (mask) { const int s = u_bit_scan(&mask); key->swizzles[s] = SWIZZLE_NOOP; key->scale_factors[s] = 0.0f; int unit_id = prog->SamplerUnits[s]; const struct gl_texture_unit *unit = &ctx->Texture.Unit[unit_id]; if (unit->_Current && unit->_Current->Target != GL_TEXTURE_BUFFER) { const struct gl_texture_object *t = unit->_Current; const struct gl_texture_image *img = t->Image[0][t->BaseLevel]; struct gl_sampler_object *sampler = _mesa_get_samplerobj(ctx, unit_id); const bool alpha_depth = t->DepthMode == GL_ALPHA && (img->_BaseFormat == GL_DEPTH_COMPONENT || img->_BaseFormat == GL_DEPTH_STENCIL); /* Haswell handles texture swizzling as surface format overrides * (except for GL_ALPHA); all other platforms need MOVs in the shader. */ if (alpha_depth || (devinfo->gen < 8 && !devinfo->is_haswell)) key->swizzles[s] = brw_get_texture_swizzle(ctx, t); if (devinfo->gen < 8 && sampler->MinFilter != GL_NEAREST && sampler->MagFilter != GL_NEAREST) { if (sampler->WrapS == GL_CLAMP) key->gl_clamp_mask[0] |= 1 << s; if (sampler->WrapT == GL_CLAMP) key->gl_clamp_mask[1] |= 1 << s; if (sampler->WrapR == GL_CLAMP) key->gl_clamp_mask[2] |= 1 << s; } /* gather4 for RG32* is broken in multiple ways on Gen7. */ if (devinfo->gen == 7 && prog->info.uses_texture_gather) { switch (img->InternalFormat) { case GL_RG32I: case GL_RG32UI: { /* We have to override the format to R32G32_FLOAT_LD. * This means that SCS_ALPHA and SCS_ONE will return 0x3f8 * (1.0) rather than integer 1. This needs shader hacks. * * On Ivybridge, we whack W (alpha) to ONE in our key's * swizzle. On Haswell, we look at the original texture * swizzle, and use XYZW with channels overridden to ONE, * leaving normal texture swizzling to SCS. */ unsigned src_swizzle = devinfo->is_haswell ? t->_Swizzle : key->swizzles[s]; for (int i = 0; i < 4; i++) { unsigned src_comp = GET_SWZ(src_swizzle, i); if (src_comp == SWIZZLE_ONE || src_comp == SWIZZLE_W) { key->swizzles[i] &= ~(0x7 << (3 * i)); key->swizzles[i] |= SWIZZLE_ONE << (3 * i); } } /* fallthrough */ } case GL_RG32F: /* The channel select for green doesn't work - we have to * request blue. Haswell can use SCS for this, but Ivybridge * needs a shader workaround. */ if (!devinfo->is_haswell) key->gather_channel_quirk_mask |= 1 << s; break; } } /* Gen6's gather4 is broken for UINT/SINT; we treat them as * UNORM/FLOAT instead and fix it in the shader. */ if (devinfo->gen == 6 && prog->info.uses_texture_gather) { key->gen6_gather_wa[s] = gen6_gather_workaround(img->InternalFormat); } /* If this is a multisample sampler, and uses the CMS MSAA layout, * then we need to emit slightly different code to first sample the * MCS surface. */ struct intel_texture_object *intel_tex = intel_texture_object((struct gl_texture_object *)t); /* From gen9 onwards some single sampled buffers can also be * compressed. These don't need ld2dms sampling along with mcs fetch. */ if (intel_tex->mt->aux_usage == ISL_AUX_USAGE_MCS) { assert(devinfo->gen >= 7); assert(intel_tex->mt->surf.samples > 1); assert(intel_tex->mt->aux_buf); assert(intel_tex->mt->surf.msaa_layout == ISL_MSAA_LAYOUT_ARRAY); key->compressed_multisample_layout_mask |= 1 << s; if (intel_tex->mt->surf.samples >= 16) { assert(devinfo->gen >= 9); key->msaa_16 |= 1 << s; } } if (t->Target == GL_TEXTURE_EXTERNAL_OES && intel_tex->planar_format) { /* Setup possible scaling factor. */ key->scale_factors[s] = intel_tex->planar_format->scaling_factor; switch (intel_tex->planar_format->components) { case __DRI_IMAGE_COMPONENTS_Y_UV: key->y_uv_image_mask |= 1 << s; break; case __DRI_IMAGE_COMPONENTS_Y_U_V: key->y_u_v_image_mask |= 1 << s; break; case __DRI_IMAGE_COMPONENTS_Y_XUXV: key->yx_xuxv_image_mask |= 1 << s; break; case __DRI_IMAGE_COMPONENTS_Y_UXVX: key->xy_uxvx_image_mask |= 1 << s; break; case __DRI_IMAGE_COMPONENTS_AYUV: key->ayuv_image_mask |= 1 << s; break; case __DRI_IMAGE_COMPONENTS_XYUV: key->xyuv_image_mask |= 1 << s; break; default: break; } } } } }
static GLboolean update_single_texture(struct st_context *st, struct pipe_sampler_view **sampler_view, GLuint texUnit) { struct pipe_context *pipe = st->pipe; struct gl_context *ctx = st->ctx; const struct gl_sampler_object *samp; struct gl_texture_object *texObj; struct st_texture_object *stObj; enum pipe_format st_view_format; GLboolean retval; samp = _mesa_get_samplerobj(ctx, texUnit); texObj = ctx->Texture.Unit[texUnit]._Current; if (!texObj) { texObj = _mesa_get_fallback_texture(ctx, TEXTURE_2D_INDEX); samp = &texObj->Sampler; } stObj = st_texture_object(texObj); retval = st_finalize_texture(ctx, st->pipe, texObj); if (!retval) { /* out of mem */ return GL_FALSE; } /* Determine the format of the texture sampler view */ st_view_format = stObj->pt->format; { const struct st_texture_image *firstImage = st_texture_image(stObj->base.Image[0][stObj->base.BaseLevel]); const gl_format texFormat = firstImage->base.TexFormat; enum pipe_format firstImageFormat = st_mesa_format_to_pipe_format(texFormat); if ((samp->sRGBDecode == GL_SKIP_DECODE_EXT) && (_mesa_get_format_color_encoding(texFormat) == GL_SRGB)) { /* Don't do sRGB->RGB conversion. Interpret the texture data as * linear values. */ const gl_format linearFormat = _mesa_get_srgb_format_linear(texFormat); firstImageFormat = st_mesa_format_to_pipe_format(linearFormat); } if (firstImageFormat != stObj->pt->format) st_view_format = firstImageFormat; } /* if sampler view has changed dereference it */ if (stObj->sampler_view) { if (check_sampler_swizzle(stObj->sampler_view, stObj->base._Swizzle, samp->DepthMode) || (st_view_format != stObj->sampler_view->format) || stObj->base.BaseLevel != stObj->sampler_view->u.tex.first_level) { pipe_sampler_view_reference(&stObj->sampler_view, NULL); } } *sampler_view = st_get_texture_sampler_view_from_stobj(stObj, pipe, samp, st_view_format); return GL_TRUE; }