static struct gl_texture_object * update_single_program_texture(struct gl_context *ctx, struct gl_program *prog, int s) { gl_texture_index target_index; struct gl_texture_unit *texUnit; struct gl_texture_object *texObj; struct gl_sampler_object *sampler; int unit; if (!(prog->SamplersUsed & (1 << s))) return NULL; unit = prog->SamplerUnits[s]; texUnit = &ctx->Texture.Unit[unit]; /* Note: If more than one bit was set in TexturesUsed[unit], then we should * have had the draw call rejected already. From the GL 4.4 specification, * section 7.10 ("Samplers"): * * "It is not allowed to have variables of different sampler types * pointing to the same texture image unit within a program * object. This situation can only be detected at the next rendering * command issued which triggers shader invocations, and an * INVALID_OPERATION error will then be generated." */ target_index = ffs(prog->TexturesUsed[unit]) - 1; texObj = texUnit->CurrentTex[target_index]; sampler = texUnit->Sampler ? texUnit->Sampler : &texObj->Sampler; if (likely(texObj)) { if (_mesa_is_texture_complete(texObj, sampler)) return texObj; _mesa_test_texobj_completeness(ctx, texObj); if (_mesa_is_texture_complete(texObj, sampler)) return texObj; } /* If we've reached this point, we didn't find a complete texture of the * shader's target. From the GL 4.4 core specification, section 11.1.3.5 * ("Texture Access"): * * "If a sampler is used in a shader and the sampler’s associated * texture is not complete, as defined in section 8.17, (0, 0, 0, 1) * will be returned for a non-shadow sampler and 0 for a shadow * sampler." * * Mesa implements this by creating a hidden texture object with a pixel of * that value. */ texObj = _mesa_get_fallback_texture(ctx, target_index); assert(texObj); return texObj; }
static void update_ff_texture_state(struct gl_context *ctx, BITSET_WORD *enabled_texture_units) { int unit; for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) { struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; GLbitfield mask; bool complete; if (texUnit->Enabled == 0x0) continue; /* If a shader already dictated what texture target was used for this * unit, just go along with it. */ if (BITSET_TEST(enabled_texture_units, unit)) continue; /* From the GL 4.4 compat specification, section 16.2 ("Texture Application"): * * "Texturing is enabled or disabled using the generic Enable and * Disable commands, respectively, with the symbolic constants * TEXTURE_1D, TEXTURE_2D, TEXTURE_RECTANGLE, TEXTURE_3D, or * TEXTURE_CUBE_MAP to enable the one-, two-, rectangular, * three-dimensional, or cube map texture, respectively. If more * than one of these textures is enabled, the first one enabled * from the following list is used: * * • cube map texture * • three-dimensional texture * • rectangular texture * • two-dimensional texture * • one-dimensional texture" * * Note that the TEXTURE_x_INDEX values are in high to low priority. * Also: * * "If a texture unit is disabled or has an invalid or incomplete * texture (as defined in section 8.17) bound to it, then blending * is disabled for that texture unit. If the texture environment * for a given enabled texture unit references a disabled texture * unit, or an invalid or incomplete texture that is bound to * another unit, then the results of texture blending are * undefined." */ complete = false; mask = texUnit->Enabled; while (mask) { const int texIndex = u_bit_scan(&mask); struct gl_texture_object *texObj = texUnit->CurrentTex[texIndex]; struct gl_sampler_object *sampler = texUnit->Sampler ? texUnit->Sampler : &texObj->Sampler; if (!_mesa_is_texture_complete(texObj, sampler)) { _mesa_test_texobj_completeness(ctx, texObj); } if (_mesa_is_texture_complete(texObj, sampler)) { _mesa_reference_texobj(&texUnit->_Current, texObj); complete = true; break; } } if (!complete) continue; /* if we get here, we know this texture unit is enabled */ BITSET_SET(enabled_texture_units, unit); ctx->Texture._MaxEnabledTexImageUnit = MAX2(ctx->Texture._MaxEnabledTexImageUnit, (int)unit); ctx->Texture._EnabledCoordUnits |= 1 << unit; update_tex_combine(ctx, texUnit); } }
/** * \note This routine refers to derived texture matrix values to * compute the ENABLE_TEXMAT flags, but is only called on * _NEW_TEXTURE. On changes to _NEW_TEXTURE_MATRIX, the ENABLE_TEXMAT * flags are updated by _mesa_update_texture_matrices, above. * * \param ctx GL context. */ static void update_texture_state( struct gl_context *ctx ) { GLuint unit; struct gl_program *fprog = NULL; struct gl_program *vprog = NULL; GLbitfield enabledFragUnits = 0x0; if (ctx->Shader.CurrentVertexProgram && ctx->Shader.CurrentVertexProgram->LinkStatus) { vprog = ctx->Shader.CurrentVertexProgram->_LinkedShaders[MESA_SHADER_VERTEX]->Program; } else if (ctx->VertexProgram._Enabled) { /* XXX enable this if/when non-shader vertex programs get * texture fetches: vprog = &ctx->VertexProgram.Current->Base; */ } if (ctx->Shader.CurrentFragmentProgram && ctx->Shader.CurrentFragmentProgram->LinkStatus) { fprog = ctx->Shader.CurrentFragmentProgram->_LinkedShaders[MESA_SHADER_FRAGMENT]->Program; } else if (ctx->FragmentProgram._Enabled) { fprog = &ctx->FragmentProgram.Current->Base; } /* FINISHME: Geometry shader texture accesses should also be considered * FINISHME: here. */ /* TODO: only set this if there are actual changes */ ctx->NewState |= _NEW_TEXTURE; ctx->Texture._EnabledUnits = 0x0; ctx->Texture._GenFlags = 0x0; ctx->Texture._TexMatEnabled = 0x0; ctx->Texture._TexGenEnabled = 0x0; /* * Update texture unit state. */ for (unit = 0; unit < ctx->Const.MaxCombinedTextureImageUnits; unit++) { struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; GLbitfield enabledVertTargets = 0x0; GLbitfield enabledFragTargets = 0x0; GLbitfield enabledTargets = 0x0; GLuint texIndex; /* Get the bitmask of texture target enables. * enableBits will be a mask of the TEXTURE_*_BIT flags indicating * which texture targets are enabled (fixed function) or referenced * by a fragment program/program. When multiple flags are set, we'll * settle on the one with highest priority (see below). */ if (vprog) { enabledVertTargets |= vprog->TexturesUsed[unit]; } if (fprog) { enabledFragTargets |= fprog->TexturesUsed[unit]; } else { /* fixed-function fragment program */ enabledFragTargets |= texUnit->Enabled; } enabledTargets = enabledVertTargets | enabledFragTargets; texUnit->_ReallyEnabled = 0x0; if (enabledTargets == 0x0) { /* neither vertex nor fragment processing uses this unit */ continue; } /* Look for the highest priority texture target that's enabled (or used * by the vert/frag shaders) and "complete". That's the one we'll use * for texturing. If we're using vert/frag program we're guaranteed * that bitcount(enabledBits) <= 1. * Note that the TEXTURE_x_INDEX values are in high to low priority. */ for (texIndex = 0; texIndex < NUM_TEXTURE_TARGETS; texIndex++) { if (enabledTargets & (1 << texIndex)) { struct gl_texture_object *texObj = texUnit->CurrentTex[texIndex]; struct gl_sampler_object *sampler = texUnit->Sampler ? texUnit->Sampler : &texObj->Sampler; if (!_mesa_is_texture_complete(texObj, sampler)) { _mesa_test_texobj_completeness(ctx, texObj); } if (_mesa_is_texture_complete(texObj, sampler)) { texUnit->_ReallyEnabled = 1 << texIndex; _mesa_reference_texobj(&texUnit->_Current, texObj); break; } } } if (!texUnit->_ReallyEnabled) { if (fprog) { /* If we get here it means the shader is expecting a texture * object, but there isn't one (or it's incomplete). Use the * fallback texture. */ struct gl_texture_object *texObj; gl_texture_index texTarget; assert(_mesa_bitcount(enabledTargets) == 1); texTarget = (gl_texture_index) (ffs(enabledTargets) - 1); texObj = _mesa_get_fallback_texture(ctx, texTarget); _mesa_reference_texobj(&texUnit->_Current, texObj); texUnit->_ReallyEnabled = 1 << texTarget; } else { /* fixed-function: texture unit is really disabled */ continue; } } /* if we get here, we know this texture unit is enabled */ ctx->Texture._EnabledUnits |= (1 << unit); if (enabledFragTargets) enabledFragUnits |= (1 << unit); update_tex_combine(ctx, texUnit); } /* Determine which texture coordinate sets are actually needed */ if (fprog) { const GLuint coordMask = (1 << MAX_TEXTURE_COORD_UNITS) - 1; ctx->Texture._EnabledCoordUnits = (fprog->InputsRead >> FRAG_ATTRIB_TEX0) & coordMask; } else {
/** * Called during state validation. When this function is finished, * the texture object should be ready for rendering. * \return GL_TRUE for success, GL_FALSE for failure (out of mem) */ GLboolean st_finalize_texture(struct gl_context *ctx, struct pipe_context *pipe, struct gl_texture_object *tObj) { struct st_context *st = st_context(ctx); struct st_texture_object *stObj = st_texture_object(tObj); const GLuint nr_faces = (stObj->base.Target == GL_TEXTURE_CUBE_MAP) ? 6 : 1; GLuint face; struct st_texture_image *firstImage; enum pipe_format firstImageFormat; GLuint ptWidth, ptHeight, ptDepth, ptLayers; if (_mesa_is_texture_complete(tObj, &tObj->Sampler)) { /* The texture is complete and we know exactly how many mipmap levels * are present/needed. This is conditional because we may be called * from the st_generate_mipmap() function when the texture object is * incomplete. In that case, we'll have set stObj->lastLevel before * we get here. */ if (stObj->base.Sampler.MinFilter == GL_LINEAR || stObj->base.Sampler.MinFilter == GL_NEAREST) stObj->lastLevel = stObj->base.BaseLevel; else stObj->lastLevel = stObj->base._MaxLevel; } firstImage = st_texture_image(stObj->base.Image[0][stObj->base.BaseLevel]); assert(firstImage); /* If both firstImage and stObj point to a texture which can contain * all active images, favour firstImage. Note that because of the * completeness requirement, we know that the image dimensions * will match. */ if (firstImage->pt && firstImage->pt != stObj->pt && (!stObj->pt || firstImage->pt->last_level >= stObj->pt->last_level)) { pipe_resource_reference(&stObj->pt, firstImage->pt); pipe_sampler_view_release(st->pipe, &stObj->sampler_view); } /* Find gallium format for the Mesa texture */ firstImageFormat = st_mesa_format_to_pipe_format(firstImage->base.TexFormat); /* Find size of level=0 Gallium mipmap image, plus number of texture layers */ { GLuint width, height, depth; if (!guess_base_level_size(stObj->base.Target, firstImage->base.Width2, firstImage->base.Height2, firstImage->base.Depth2, firstImage->base.Level, &width, &height, &depth)) { width = stObj->width0; height = stObj->height0; depth = stObj->depth0; } /* convert GL dims to Gallium dims */ st_gl_texture_dims_to_pipe_dims(stObj->base.Target, width, height, depth, &ptWidth, &ptHeight, &ptDepth, &ptLayers); } /* If we already have a gallium texture, check that it matches the texture * object's format, target, size, num_levels, etc. */ if (stObj->pt) { if (stObj->pt->target != gl_target_to_pipe(stObj->base.Target) || !st_sampler_compat_formats(stObj->pt->format, firstImageFormat) || stObj->pt->last_level < stObj->lastLevel || stObj->pt->width0 != ptWidth || stObj->pt->height0 != ptHeight || stObj->pt->depth0 != ptDepth || stObj->pt->array_size != ptLayers) { /* The gallium texture does not match the Mesa texture so delete the * gallium texture now. We'll make a new one below. */ pipe_resource_reference(&stObj->pt, NULL); pipe_sampler_view_release(st->pipe, &stObj->sampler_view); st->dirty.st |= ST_NEW_FRAMEBUFFER; } } /* May need to create a new gallium texture: */ if (!stObj->pt) { GLuint bindings = default_bindings(st, firstImageFormat); stObj->pt = st_texture_create(st, gl_target_to_pipe(stObj->base.Target), firstImageFormat, stObj->lastLevel, ptWidth, ptHeight, ptDepth, ptLayers, bindings); if (!stObj->pt) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage"); return GL_FALSE; } } /* Pull in any images not in the object's texture: */ for (face = 0; face < nr_faces; face++) { GLuint level; for (level = stObj->base.BaseLevel; level <= stObj->lastLevel; level++) { struct st_texture_image *stImage = st_texture_image(stObj->base.Image[face][level]); /* Need to import images in main memory or held in other textures. */ if (stImage && stObj->pt != stImage->pt) { if (level == 0 || (stImage->base.Width == u_minify(stObj->width0, level) && stImage->base.Height == u_minify(stObj->height0, level) && stImage->base.Depth == u_minify(stObj->depth0, level))) { /* src image fits expected dest mipmap level size */ copy_image_data_to_texture(st, stObj, level, stImage); } } } } return GL_TRUE; }
/** * \note This routine refers to derived texture matrix values to * compute the ENABLE_TEXMAT flags, but is only called on * _NEW_TEXTURE. On changes to _NEW_TEXTURE_MATRIX, the ENABLE_TEXMAT * flags are updated by _mesa_update_texture_matrices, above. * * \param ctx GL context. */ static void update_texture_state( struct gl_context *ctx ) { GLuint unit; struct gl_program *prog[MESA_SHADER_STAGES]; GLbitfield enabledFragUnits = 0x0; int i; for (i = 0; i < MESA_SHADER_STAGES; i++) { if (ctx->Shader.CurrentProgram[i] && ctx->Shader.CurrentProgram[i]->LinkStatus) { prog[i] = ctx->Shader.CurrentProgram[i]->_LinkedShaders[i]->Program; } else { if (i == MESA_SHADER_FRAGMENT && ctx->FragmentProgram._Enabled) prog[i] = &ctx->FragmentProgram.Current->Base; else prog[i] = NULL; } } /* TODO: only set this if there are actual changes */ ctx->NewState |= _NEW_TEXTURE; ctx->Texture._EnabledUnits = 0x0; ctx->Texture._GenFlags = 0x0; ctx->Texture._TexMatEnabled = 0x0; ctx->Texture._TexGenEnabled = 0x0; /* * Update texture unit state. */ for (unit = 0; unit < ctx->Const.MaxCombinedTextureImageUnits; unit++) { struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; GLbitfield enabledTargetsByStage[MESA_SHADER_STAGES]; GLbitfield enabledTargets = 0x0; GLuint texIndex; /* Get the bitmask of texture target enables. * enableBits will be a mask of the TEXTURE_*_BIT flags indicating * which texture targets are enabled (fixed function) or referenced * by a fragment program/program. When multiple flags are set, we'll * settle on the one with highest priority (see below). */ for (i = 0; i < MESA_SHADER_STAGES; i++) { if (prog[i]) enabledTargetsByStage[i] = prog[i]->TexturesUsed[unit]; else if (i == MESA_SHADER_FRAGMENT) enabledTargetsByStage[i] = texUnit->Enabled; else enabledTargetsByStage[i] = 0; enabledTargets |= enabledTargetsByStage[i]; } texUnit->_ReallyEnabled = 0x0; if (enabledTargets == 0x0) { /* neither vertex nor fragment processing uses this unit */ continue; } /* Look for the highest priority texture target that's enabled (or used * by the vert/frag shaders) and "complete". That's the one we'll use * for texturing. * * Note that the TEXTURE_x_INDEX values are in high to low priority. */ for (texIndex = 0; texIndex < NUM_TEXTURE_TARGETS; texIndex++) { if (enabledTargets & (1 << texIndex)) { struct gl_texture_object *texObj = texUnit->CurrentTex[texIndex]; struct gl_sampler_object *sampler = texUnit->Sampler ? texUnit->Sampler : &texObj->Sampler; if (!_mesa_is_texture_complete(texObj, sampler)) { _mesa_test_texobj_completeness(ctx, texObj); } if (_mesa_is_texture_complete(texObj, sampler)) { texUnit->_ReallyEnabled = 1 << texIndex; _mesa_reference_texobj(&texUnit->_Current, texObj); break; } } } if (!texUnit->_ReallyEnabled) { if (prog[MESA_SHADER_FRAGMENT]) { /* If we get here it means the shader is expecting a texture * object, but there isn't one (or it's incomplete). Use the * fallback texture. */ struct gl_texture_object *texObj; gl_texture_index texTarget; texTarget = (gl_texture_index) (ffs(enabledTargets) - 1); texObj = _mesa_get_fallback_texture(ctx, texTarget); assert(texObj); if (!texObj) { /* invalid fallback texture: don't enable the texture unit */ continue; } _mesa_reference_texobj(&texUnit->_Current, texObj); texUnit->_ReallyEnabled = 1 << texTarget; } else { /* fixed-function: texture unit is really disabled */ continue; } } /* if we get here, we know this texture unit is enabled */ ctx->Texture._EnabledUnits |= (1 << unit); if (enabledTargetsByStage[MESA_SHADER_FRAGMENT]) enabledFragUnits |= (1 << unit); if (!prog[MESA_SHADER_FRAGMENT]) update_tex_combine(ctx, texUnit); } /* Determine which texture coordinate sets are actually needed */ if (prog[MESA_SHADER_FRAGMENT]) { const GLuint coordMask = (1 << MAX_TEXTURE_COORD_UNITS) - 1; ctx->Texture._EnabledCoordUnits = (prog[MESA_SHADER_FRAGMENT]->InputsRead >> VARYING_SLOT_TEX0) & coordMask; } else {