static __DRIimage * intel_create_image_from_texture(__DRIcontext *context, int target, unsigned texture, int zoffset, int level, unsigned *error, void *loaderPrivate) { __DRIimage *image; struct brw_context *brw = context->driverPrivate; struct gl_texture_object *obj; struct intel_texture_object *iobj; GLuint face = 0; obj = _mesa_lookup_texture(&brw->ctx, texture); if (!obj || obj->Target != target) { *error = __DRI_IMAGE_ERROR_BAD_PARAMETER; return NULL; } if (target == GL_TEXTURE_CUBE_MAP) face = zoffset; _mesa_test_texobj_completeness(&brw->ctx, obj); iobj = intel_texture_object(obj); if (!obj->_BaseComplete || (level > 0 && !obj->_MipmapComplete)) { *error = __DRI_IMAGE_ERROR_BAD_PARAMETER; return NULL; } if (level < obj->BaseLevel || level > obj->_MaxLevel) { *error = __DRI_IMAGE_ERROR_BAD_MATCH; return NULL; } if (target == GL_TEXTURE_3D && obj->Image[face][level]->Depth < zoffset) { *error = __DRI_IMAGE_ERROR_BAD_MATCH; return NULL; } image = calloc(1, sizeof *image); if (image == NULL) { *error = __DRI_IMAGE_ERROR_BAD_ALLOC; return NULL; } image->internal_format = obj->Image[face][level]->InternalFormat; image->format = obj->Image[face][level]->TexFormat; image->data = loaderPrivate; intel_setup_image_from_mipmap_tree(brw, image, iobj->mt, level, zoffset); image->dri_format = driGLFormatToImageFormat(image->format); image->has_depthstencil = iobj->mt->stencil_mt? true : false; if (image->dri_format == MESA_FORMAT_NONE) { *error = __DRI_IMAGE_ERROR_BAD_PARAMETER; free(image); return NULL; } *error = __DRI_IMAGE_ERROR_SUCCESS; return image; }
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; }
GLboolean _mesa_is_image_unit_valid(struct gl_context *ctx, struct gl_image_unit *u) { struct gl_texture_object *t = u->TexObj; mesa_format tex_format; if (!t) return GL_FALSE; if (!t->_BaseComplete && !t->_MipmapComplete) _mesa_test_texobj_completeness(ctx, t); if (u->Level < t->BaseLevel || u->Level > t->_MaxLevel || (u->Level == t->BaseLevel && !t->_BaseComplete) || (u->Level != t->BaseLevel && !t->_MipmapComplete)) return GL_FALSE; if (_mesa_tex_target_is_layered(t->Target) && u->_Layer >= _mesa_get_texture_layers(t, u->Level)) return GL_FALSE; if (t->Target == GL_TEXTURE_BUFFER) { tex_format = _mesa_get_shader_image_format(t->BufferObjectFormat); } else { struct gl_texture_image *img = (t->Target == GL_TEXTURE_CUBE_MAP ? t->Image[u->_Layer][u->Level] : t->Image[0][u->Level]); if (!img || img->Border || img->NumSamples > ctx->Const.MaxImageSamples) return GL_FALSE; tex_format = _mesa_get_shader_image_format(img->InternalFormat); } if (!tex_format) return GL_FALSE; switch (t->ImageFormatCompatibilityType) { case GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE: if (_mesa_get_format_bytes(tex_format) != _mesa_get_format_bytes(u->_ActualFormat)) return GL_FALSE; break; case GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS: if (get_image_format_class(tex_format) != get_image_format_class(u->_ActualFormat)) return GL_FALSE; break; default: assert(!"Unexpected image format compatibility type"); } return GL_TRUE; }
static GLboolean validate_image_unit(struct gl_context *ctx, struct gl_image_unit *u) { struct gl_texture_object *t = u->TexObj; struct gl_texture_image *img; if (!t || u->Level < t->BaseLevel || u->Level > t->_MaxLevel) return GL_FALSE; _mesa_test_texobj_completeness(ctx, t); if ((u->Level == t->BaseLevel && !t->_BaseComplete) || (u->Level != t->BaseLevel && !t->_MipmapComplete)) return GL_FALSE; if (_mesa_tex_target_is_layered(t->Target) && u->Layer >= _mesa_get_texture_layers(t, u->Level)) return GL_FALSE; if (t->Target == GL_TEXTURE_CUBE_MAP) img = t->Image[u->Layer][u->Level]; else img = t->Image[0][u->Level]; if (!img || img->Border || get_image_format_class(img->TexFormat) == IMAGE_FORMAT_CLASS_NONE || img->NumSamples > ctx->Const.MaxImageSamples) return GL_FALSE; switch (t->ImageFormatCompatibilityType) { case GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE: if (_mesa_get_format_bytes(img->TexFormat) != _mesa_get_format_bytes(u->_ActualFormat)) return GL_FALSE; break; case GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS: if (get_image_format_class(img->TexFormat) != get_image_format_class(u->_ActualFormat)) return GL_FALSE; break; default: assert(!"Unexpected image format compatibility type"); } return GL_TRUE; }
/** * Return pointer to a default/fallback texture. * The texture is a 2D 8x8 RGBA texture with all texels = (0,0,0,1). * That's the value a sampler should get when sampling from an * incomplete texture. */ struct gl_texture_object * _mesa_get_fallback_texture(struct gl_context *ctx) { if (!ctx->Shared->FallbackTex) { /* create fallback texture now */ static GLubyte texels[8 * 8][4]; struct gl_texture_object *texObj; struct gl_texture_image *texImage; gl_format texFormat; GLuint i; for (i = 0; i < 8 * 8; i++) { texels[i][0] = texels[i][1] = texels[i][2] = 0x0; texels[i][3] = 0xff; } /* create texture object */ texObj = ctx->Driver.NewTextureObject(ctx, 0, GL_TEXTURE_2D); assert(texObj->RefCount == 1); texObj->Sampler.MinFilter = GL_NEAREST; texObj->Sampler.MagFilter = GL_NEAREST; /* create level[0] texture image */ texImage = _mesa_get_tex_image(ctx, texObj, GL_TEXTURE_2D, 0); texFormat = ctx->Driver.ChooseTextureFormat(ctx, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE); /* init the image fields */ _mesa_init_teximage_fields(ctx, texImage, 8, 8, 1, 0, GL_RGBA, texFormat); ASSERT(texImage->TexFormat != MESA_FORMAT_NONE); /* set image data */ ctx->Driver.TexImage2D(ctx, texImage, GL_RGBA, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, texels, &ctx->DefaultPacking); _mesa_test_texobj_completeness(ctx, texObj); assert(texObj->_Complete); ctx->Shared->FallbackTex = texObj; } return ctx->Shared->FallbackTex; }
/** * Return pointer to a default/fallback texture of the given type/target. * The texture is an RGBA texture with all texels = (0,0,0,1). * That's the value a GLSL sampler should get when sampling from an * incomplete texture. */ struct gl_texture_object * _mesa_get_fallback_texture(struct gl_context *ctx, gl_texture_index tex) { if (!ctx->Shared->FallbackTex[tex]) { /* create fallback texture now */ const GLsizei width = 1, height = 1, depth = 1; GLubyte texel[4]; struct gl_texture_object *texObj; struct gl_texture_image *texImage; gl_format texFormat; GLuint dims, face, numFaces = 1; GLenum target; texel[0] = texel[1] = texel[2] = 0x0; texel[3] = 0xff; switch (tex) { case TEXTURE_2D_ARRAY_INDEX: dims = 3; target = GL_TEXTURE_2D_ARRAY; break; case TEXTURE_1D_ARRAY_INDEX: dims = 2; target = GL_TEXTURE_1D_ARRAY; break; case TEXTURE_CUBE_INDEX: dims = 2; target = GL_TEXTURE_CUBE_MAP; numFaces = 6; break; case TEXTURE_3D_INDEX: dims = 3; target = GL_TEXTURE_3D; break; case TEXTURE_RECT_INDEX: dims = 2; target = GL_TEXTURE_RECTANGLE; break; case TEXTURE_2D_INDEX: dims = 2; target = GL_TEXTURE_2D; break; case TEXTURE_1D_INDEX: dims = 1; target = GL_TEXTURE_1D; break; case TEXTURE_BUFFER_INDEX: dims = 0; target = GL_TEXTURE_BUFFER; break; case TEXTURE_EXTERNAL_INDEX: default: /* no-op */ return NULL; } /* create texture object */ texObj = ctx->Driver.NewTextureObject(ctx, 0, target); if (!texObj) return NULL; assert(texObj->RefCount == 1); texObj->Sampler.MinFilter = GL_NEAREST; texObj->Sampler.MagFilter = GL_NEAREST; texFormat = ctx->Driver.ChooseTextureFormat(ctx, target, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE); /* need a loop here just for cube maps */ for (face = 0; face < numFaces; face++) { GLenum faceTarget; if (target == GL_TEXTURE_CUBE_MAP) faceTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face; else faceTarget = target; /* initialize level[0] texture image */ texImage = _mesa_get_tex_image(ctx, texObj, faceTarget, 0); _mesa_init_teximage_fields(ctx, texImage, width, (dims > 1) ? height : 1, (dims > 2) ? depth : 1, 0, /* border */ GL_RGBA, texFormat); ctx->Driver.TexImage(ctx, dims, texImage, GL_RGBA, GL_UNSIGNED_BYTE, texel, &ctx->DefaultPacking); } _mesa_test_texobj_completeness(ctx, texObj); assert(texObj->_BaseComplete); assert(texObj->_MipmapComplete); ctx->Shared->FallbackTex[tex] = texObj; } return ctx->Shared->FallbackTex[tex]; }
static __DRIimage * dri2_create_from_texture(__DRIcontext *context, int target, unsigned texture, int depth, int level, unsigned *error, void *loaderPrivate) { __DRIimage *img; struct gl_context *ctx = ((struct st_context *)dri_context(context)->st)->ctx; struct gl_texture_object *obj; struct pipe_resource *tex; GLuint face = 0; obj = _mesa_lookup_texture(ctx, texture); if (!obj || obj->Target != target) { *error = __DRI_IMAGE_ERROR_BAD_PARAMETER; return NULL; } tex = st_get_texobj_resource(obj); if (!tex) { *error = __DRI_IMAGE_ERROR_BAD_PARAMETER; return NULL; } if (target == GL_TEXTURE_CUBE_MAP) face = depth; _mesa_test_texobj_completeness(ctx, obj); if (!obj->_BaseComplete || (level > 0 && !obj->_MipmapComplete)) { *error = __DRI_IMAGE_ERROR_BAD_PARAMETER; return NULL; } if (level < obj->BaseLevel || level > obj->_MaxLevel) { *error = __DRI_IMAGE_ERROR_BAD_MATCH; return NULL; } if (target == GL_TEXTURE_3D && obj->Image[face][level]->Depth < depth) { *error = __DRI_IMAGE_ERROR_BAD_MATCH; return NULL; } img = CALLOC_STRUCT(__DRIimageRec); if (!img) { *error = __DRI_IMAGE_ERROR_BAD_ALLOC; return NULL; } img->level = level; img->layer = depth; img->dri_format = driGLFormatToImageFormat(obj->Image[face][level]->TexFormat); img->loader_private = loaderPrivate; if (img->dri_format == __DRI_IMAGE_FORMAT_NONE) { *error = __DRI_IMAGE_ERROR_BAD_PARAMETER; free(img); return NULL; } pipe_resource_reference(&img->texture, tex); *error = __DRI_IMAGE_ERROR_SUCCESS; return img; }
/** * Prepare the source or destination resource, including: * - Error checking * - Creating texture wrappers for renderbuffers * \param name the texture or renderbuffer name * \param target GL_TEXTURE target or GL_RENDERBUFFER. For the later, will * be changed to a compatible GL_TEXTURE target. * \param level mipmap level * \param tex_obj returns a pointer to a texture object * \param tex_image returns a pointer to a texture image * \param tmp_tex returns temporary texture object name * \return true if success, false if error */ static bool prepare_target(struct gl_context *ctx, GLuint name, GLenum *target, int level, struct gl_texture_object **tex_obj, struct gl_texture_image **tex_image, GLuint *tmp_tex, const char *dbg_prefix) { if (name == 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glCopyImageSubData(%sName = %d)", dbg_prefix, name); return false; } /* * INVALID_ENUM is generated * * if either <srcTarget> or <dstTarget> * - is not RENDERBUFFER or a valid non-proxy texture target * - is TEXTURE_BUFFER, or * - is one of the cubemap face selectors described in table 3.17, */ switch (*target) { case GL_RENDERBUFFER: /* Not a texture target, but valid */ case GL_TEXTURE_1D: case GL_TEXTURE_1D_ARRAY: case GL_TEXTURE_2D: case GL_TEXTURE_3D: case GL_TEXTURE_CUBE_MAP: case GL_TEXTURE_RECTANGLE: case GL_TEXTURE_2D_ARRAY: case GL_TEXTURE_CUBE_MAP_ARRAY: case GL_TEXTURE_2D_MULTISAMPLE: case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: /* These are all valid */ break; case GL_TEXTURE_EXTERNAL_OES: /* Only exists in ES */ case GL_TEXTURE_BUFFER: default: _mesa_error(ctx, GL_INVALID_ENUM, "glCopyImageSubData(%sTarget = %s)", dbg_prefix, _mesa_lookup_enum_by_nr(*target)); return false; } if (*target == GL_RENDERBUFFER) { struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, name); if (!rb) { _mesa_error(ctx, GL_INVALID_VALUE, "glCopyImageSubData(%sName = %u)", dbg_prefix, name); return false; } if (!rb->Name) { _mesa_error(ctx, GL_INVALID_OPERATION, "glCopyImageSubData(%sName incomplete)", dbg_prefix); return false; } if (level != 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glCopyImageSubData(%sLevel = %u)", dbg_prefix, level); return false; } if (rb->NumSamples > 1) *target = GL_TEXTURE_2D_MULTISAMPLE; else *target = GL_TEXTURE_2D; *tmp_tex = 0; _mesa_GenTextures(1, tmp_tex); if (*tmp_tex == 0) return false; /* Error already set by GenTextures */ _mesa_BindTexture(*target, *tmp_tex); *tex_obj = _mesa_lookup_texture(ctx, *tmp_tex); *tex_image = _mesa_get_tex_image(ctx, *tex_obj, *target, 0); if (!ctx->Driver.BindRenderbufferTexImage(ctx, rb, *tex_image)) { _mesa_problem(ctx, "Failed to create texture from renderbuffer"); return false; } if (ctx->Driver.FinishRenderTexture && !rb->NeedsFinishRenderTexture) { rb->NeedsFinishRenderTexture = true; ctx->Driver.FinishRenderTexture(ctx, rb); } } else { *tex_obj = _mesa_lookup_texture(ctx, name); if (!*tex_obj) { _mesa_error(ctx, GL_INVALID_VALUE, "glCopyImageSubData(%sName = %u)", dbg_prefix, name); return false; } _mesa_test_texobj_completeness(ctx, *tex_obj); if (!(*tex_obj)->_BaseComplete || (level != 0 && !(*tex_obj)->_MipmapComplete)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glCopyImageSubData(%sName incomplete)", dbg_prefix); return false; } if ((*tex_obj)->Target != *target) { _mesa_error(ctx, GL_INVALID_ENUM, "glCopyImageSubData(%sTarget = %s)", dbg_prefix, _mesa_lookup_enum_by_nr(*target)); return false; } if (level < 0 || level >= MAX_TEXTURE_LEVELS) { _mesa_error(ctx, GL_INVALID_VALUE, "glCopyImageSubData(%sLevel = %d)", dbg_prefix, level); return false; } *tex_image = _mesa_select_tex_image(*tex_obj, *target, level); if (!*tex_image) { _mesa_error(ctx, GL_INVALID_VALUE, "glCopyImageSubData(%sLevel = %u)", dbg_prefix, level); return false; } } return true; }
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. * * If both TEXTURE and TEXTURE_MATRIX change at once, these values * will be computed twice. */ static void update_texture_state( GLcontext *ctx ) { GLuint i; ctx->Texture._ReallyEnabled = 0; ctx->Texture._GenFlags = 0; ctx->_NeedNormals &= ~NEED_NORMALS_TEXGEN; ctx->_NeedEyeCoords &= ~NEED_EYE_TEXGEN; ctx->Texture._TexMatEnabled = 0; ctx->Texture._TexGenEnabled = 0; /* Update texture unit state. */ for (i=0; i < ctx->Const.MaxTextureUnits; i++) { struct gl_texture_unit *texUnit = &ctx->Texture.Unit[i]; texUnit->_ReallyEnabled = 0; texUnit->_GenFlags = 0; if (!texUnit->Enabled) continue; /* Find the texture of highest dimensionality that is enabled * and complete. We'll use it for texturing. */ if (texUnit->Enabled & TEXTURE0_CUBE) { struct gl_texture_object *texObj = texUnit->CurrentCubeMap; if (!texObj->Complete) { _mesa_test_texobj_completeness(ctx, texObj); } if (texObj->Complete) { texUnit->_ReallyEnabled = TEXTURE0_CUBE; texUnit->_Current = texObj; } } if (!texUnit->_ReallyEnabled && (texUnit->Enabled & TEXTURE0_3D)) { struct gl_texture_object *texObj = texUnit->Current3D; if (!texObj->Complete) { _mesa_test_texobj_completeness(ctx, texObj); } if (texObj->Complete) { texUnit->_ReallyEnabled = TEXTURE0_3D; texUnit->_Current = texObj; } } if (!texUnit->_ReallyEnabled && (texUnit->Enabled & TEXTURE0_RECT)) { struct gl_texture_object *texObj = texUnit->CurrentRect; if (!texObj->Complete) { _mesa_test_texobj_completeness(ctx, texObj); } if (texObj->Complete) { texUnit->_ReallyEnabled = TEXTURE0_RECT; texUnit->_Current = texObj; } } if (!texUnit->_ReallyEnabled && (texUnit->Enabled & TEXTURE0_2D)) { struct gl_texture_object *texObj = texUnit->Current2D; if (!texObj->Complete) { _mesa_test_texobj_completeness(ctx, texObj); } if (texObj->Complete) { texUnit->_ReallyEnabled = TEXTURE0_2D; texUnit->_Current = texObj; } } if (!texUnit->_ReallyEnabled && (texUnit->Enabled & TEXTURE0_1D)) { struct gl_texture_object *texObj = texUnit->Current1D; if (!texObj->Complete) { _mesa_test_texobj_completeness(ctx, texObj); } if (texObj->Complete) { texUnit->_ReallyEnabled = TEXTURE0_1D; texUnit->_Current = texObj; } } if (!texUnit->_ReallyEnabled) { texUnit->_Current = NULL; continue; } { GLuint flag = texUnit->_ReallyEnabled << (i * NUM_TEXTURE_TARGETS); ctx->Texture._ReallyEnabled |= flag; } if (texUnit->TexGenEnabled) { if (texUnit->TexGenEnabled & S_BIT) { texUnit->_GenFlags |= texUnit->_GenBitS; } if (texUnit->TexGenEnabled & T_BIT) { texUnit->_GenFlags |= texUnit->_GenBitT; } if (texUnit->TexGenEnabled & Q_BIT) { texUnit->_GenFlags |= texUnit->_GenBitQ; } if (texUnit->TexGenEnabled & R_BIT) { texUnit->_GenFlags |= texUnit->_GenBitR; } ctx->Texture._TexGenEnabled |= ENABLE_TEXGEN(i); ctx->Texture._GenFlags |= texUnit->_GenFlags; } if (ctx->TextureMatrix[i].type != MATRIX_IDENTITY) ctx->Texture._TexMatEnabled |= ENABLE_TEXMAT(i); } if (ctx->Texture._GenFlags & TEXGEN_NEED_NORMALS) { ctx->_NeedNormals |= NEED_NORMALS_TEXGEN; ctx->_NeedEyeCoords |= NEED_EYE_TEXGEN; } if (ctx->Texture._GenFlags & TEXGEN_NEED_EYE_COORD) { ctx->_NeedEyeCoords |= NEED_EYE_TEXGEN; } }
/** * \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( GLcontext *ctx ) { GLuint unit; struct gl_fragment_program *fprog = NULL; struct gl_vertex_program *vprog = NULL; GLbitfield enabledFragUnits = 0x0; if (ctx->Shader.CurrentProgram && ctx->Shader.CurrentProgram->LinkStatus) { fprog = ctx->Shader.CurrentProgram->FragmentProgram; vprog = ctx->Shader.CurrentProgram->VertexProgram; } else { if (ctx->FragmentProgram._Enabled) { fprog = ctx->FragmentProgram.Current; } if (ctx->VertexProgram._Enabled) { /* XXX enable this if/when non-shader vertex programs get * texture fetches: vprog = ctx->VertexProgram.Current; */ } } /* 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.MaxTextureImageUnits; 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 shader/program. When multiple flags are set, we'll * settle on the one with highest priority (see below). */ if (vprog) { enabledVertTargets |= vprog->Base.TexturesUsed[unit]; } if (fprog) { enabledFragTargets |= fprog->Base.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]; if (!texObj->_Complete) { _mesa_test_texobj_completeness(ctx, texObj); } if (texObj->_Complete) { 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 = _mesa_get_fallback_texture(ctx); texUnit->_ReallyEnabled = 1 << TEXTURE_2D_INDEX; _mesa_reference_texobj(&texUnit->_Current, texObj); } 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->Base.InputsRead >> FRAG_ATTRIB_TEX0) & coordMask; } else {
/** * \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; struct gl_program *gprog = NULL; GLbitfield enabledFragUnits = 0x0; if (ctx->Shader.CurrentVertexProgram && ctx->Shader.CurrentVertexProgram->LinkStatus) { vprog = ctx->Shader.CurrentVertexProgram->_LinkedShaders[MESA_SHADER_VERTEX]->Program; } if (ctx->Shader.CurrentGeometryProgram && ctx->Shader.CurrentGeometryProgram->LinkStatus) { gprog = ctx->Shader.CurrentGeometryProgram->_LinkedShaders[MESA_SHADER_GEOMETRY]->Program; } 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; } /* 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 enabledGeomTargets = 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 (gprog) { enabledGeomTargets |= gprog->TexturesUsed[unit]; } if (fprog) { enabledFragTargets |= fprog->TexturesUsed[unit]; } else { /* fixed-function fragment program */ enabledFragTargets |= texUnit->Enabled; } enabledTargets = enabledVertTargets | enabledFragTargets | enabledGeomTargets; 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 (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; 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 (enabledFragTargets) enabledFragUnits |= (1 << unit); if (!fprog) 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 >> VARYING_SLOT_TEX0) & coordMask; } else {
/** * Prepare the source or destination resource. This involves error * checking and returning the relevant gl_texture_image or gl_renderbuffer. * Note that one of the resulting tex_image or renderbuffer pointers will be * NULL and the other will be non-null. * * \param name the texture or renderbuffer name * \param target One of GL_TEXTURE_x target or GL_RENDERBUFFER * \param level mipmap level * \param z src or dest Z * \param depth number of slices/faces/layers to copy * \param tex_image returns a pointer to a texture image * \param renderbuffer returns a pointer to a renderbuffer * \return true if success, false if error */ static bool prepare_target(struct gl_context *ctx, GLuint name, GLenum target, int level, int z, int depth, struct gl_texture_image **tex_image, struct gl_renderbuffer **renderbuffer, mesa_format *format, GLenum *internalFormat, GLuint *width, GLuint *height, GLuint *num_samples, const char *dbg_prefix) { if (name == 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glCopyImageSubData(%sName = %d)", dbg_prefix, name); return false; } /* * INVALID_ENUM is generated * * if either <srcTarget> or <dstTarget> * - is not RENDERBUFFER or a valid non-proxy texture target * - is TEXTURE_BUFFER, or * - is one of the cubemap face selectors described in table 3.17, */ switch (target) { case GL_RENDERBUFFER: /* Not a texture target, but valid */ case GL_TEXTURE_1D: case GL_TEXTURE_1D_ARRAY: case GL_TEXTURE_2D: case GL_TEXTURE_3D: case GL_TEXTURE_CUBE_MAP: case GL_TEXTURE_RECTANGLE: case GL_TEXTURE_2D_ARRAY: case GL_TEXTURE_CUBE_MAP_ARRAY: case GL_TEXTURE_2D_MULTISAMPLE: case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: /* These are all valid */ break; case GL_TEXTURE_EXTERNAL_OES: /* Only exists in ES */ case GL_TEXTURE_BUFFER: default: _mesa_error(ctx, GL_INVALID_ENUM, "glCopyImageSubData(%sTarget = %s)", dbg_prefix, _mesa_enum_to_string(target)); return false; } if (target == GL_RENDERBUFFER) { struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, name); if (!rb) { _mesa_error(ctx, GL_INVALID_VALUE, "glCopyImageSubData(%sName = %u)", dbg_prefix, name); return false; } if (!rb->Name) { _mesa_error(ctx, GL_INVALID_OPERATION, "glCopyImageSubData(%sName incomplete)", dbg_prefix); return false; } if (level != 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glCopyImageSubData(%sLevel = %u)", dbg_prefix, level); return false; } *renderbuffer = rb; *format = rb->Format; *internalFormat = rb->InternalFormat; *width = rb->Width; *height = rb->Height; *num_samples = rb->NumSamples; *tex_image = NULL; } else { struct gl_texture_object *texObj = _mesa_lookup_texture(ctx, name); if (!texObj) { /* * From GL_ARB_copy_image specification: * "INVALID_VALUE is generated if either <srcName> or <dstName> does * not correspond to a valid renderbuffer or texture object according * to the corresponding target parameter." */ _mesa_error(ctx, GL_INVALID_VALUE, "glCopyImageSubData(%sName = %u)", dbg_prefix, name); return false; } _mesa_test_texobj_completeness(ctx, texObj); if (!texObj->_BaseComplete || (level != 0 && !texObj->_MipmapComplete)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glCopyImageSubData(%sName incomplete)", dbg_prefix); return false; } /* Note that target will not be a cube face name */ if (texObj->Target != target) { /* * From GL_ARB_copy_image_specification: * "INVALID_ENUM is generated if the target does not match the type * of the object." */ _mesa_error(ctx, GL_INVALID_ENUM, "glCopyImageSubData(%sTarget = %s)", dbg_prefix, _mesa_enum_to_string(target)); return false; } if (level < 0 || level >= MAX_TEXTURE_LEVELS) { _mesa_error(ctx, GL_INVALID_VALUE, "glCopyImageSubData(%sLevel = %d)", dbg_prefix, level); return false; } if (target == GL_TEXTURE_CUBE_MAP) { int i; assert(z < MAX_FACES); /* should have been caught earlier */ /* make sure all the cube faces are present */ for (i = 0; i < depth; i++) { if (!texObj->Image[z+i][level]) { /* missing cube face */ _mesa_error(ctx, GL_INVALID_VALUE, "glCopyImageSubData(missing cube face)"); return false; } } *tex_image = texObj->Image[z][level]; } else { *tex_image = _mesa_select_tex_image(texObj, target, level); } if (!*tex_image) { _mesa_error(ctx, GL_INVALID_VALUE, "glCopyImageSubData(%sLevel = %u)", dbg_prefix, level); return false; } *renderbuffer = NULL; *format = (*tex_image)->TexFormat; *internalFormat = (*tex_image)->InternalFormat; *width = (*tex_image)->Width; *height = (*tex_image)->Height; *num_samples = (*tex_image)->NumSamples; } return true; }