/** * Set texture priorities. * * \param n number of textures. * \param texName texture names. * \param priorities corresponding texture priorities. * * \sa glPrioritizeTextures(). * * Looks up each texture in the hash, clamps the corresponding priority between * 0.0 and 1.0, and calls dd_function_table::PrioritizeTexture. */ void GLAPIENTRY _mesa_PrioritizeTextures( GLsizei n, const GLuint *texName, const GLclampf *priorities ) { GET_CURRENT_CONTEXT(ctx); GLint i; ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); if (n < 0) { _mesa_error( ctx, GL_INVALID_VALUE, "glPrioritizeTextures" ); return; } if (!priorities) return; for (i = 0; i < n; i++) { if (texName[i] > 0) { struct gl_texture_object *t = _mesa_lookup_texture(ctx, texName[i]); if (t) { t->Priority = CLAMP( priorities[i], 0.0F, 1.0F ); } } } ctx->NewState |= _NEW_TEXTURE; }
/** * Set texture priorities. * * \param n number of textures. * \param texName texture names. * \param priorities corresponding texture priorities. * * \sa glPrioritizeTextures(). * * Looks up each texture in the hash, clamps the corresponding priority between * 0.0 and 1.0, and calls dd_function_table::PrioritizeTexture. */ void GLAPIENTRY _mesa_PrioritizeTextures( GLsizei n, const GLuint *texName, const GLclampf *priorities ) { GET_CURRENT_CONTEXT(ctx); GLint i; if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) _mesa_debug(ctx, "glPrioritizeTextures %d\n", n); FLUSH_VERTICES(ctx, 0); if (n < 0) { _mesa_error( ctx, GL_INVALID_VALUE, "glPrioritizeTextures" ); return; } if (!priorities) return; for (i = 0; i < n; i++) { if (texName[i] > 0) { struct gl_texture_object *t = _mesa_lookup_texture(ctx, texName[i]); if (t) { t->Priority = CLAMP( priorities[i], 0.0F, 1.0F ); } } } ctx->NewState |= _NEW_TEXTURE; }
GLboolean _mesa_meta_bind_rb_as_tex_image(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint *tex, struct gl_texture_object **texObj, GLenum *target) { struct gl_texture_image *texImage; if (rb->NumSamples > 1) *target = GL_TEXTURE_2D_MULTISAMPLE; else *target = GL_TEXTURE_2D; _mesa_GenTextures(1, tex); _mesa_BindTexture(*target, *tex); *texObj = _mesa_lookup_texture(ctx, *tex); texImage = _mesa_get_tex_image(ctx, *texObj, *target, 0); if (!ctx->Driver.BindRenderbufferTexImage(ctx, rb, texImage)) { _mesa_DeleteTextures(1, tex); return false; } if (ctx->Driver.FinishRenderTexture && !rb->NeedsFinishRenderTexture) { rb->NeedsFinishRenderTexture = true; ctx->Driver.FinishRenderTexture(ctx, rb); } return true; }
void GLAPIENTRY _mesa_BindImageTexture(GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format) { GET_CURRENT_CONTEXT(ctx); struct gl_image_unit *u; if (!validate_bind_image_texture(ctx, unit, texture, level, layered, layer, access, format)) return; u = &ctx->ImageUnits[unit]; FLUSH_VERTICES(ctx, 0); ctx->NewDriverState |= ctx->DriverFlags.NewImageUnits; if (texture) { struct gl_texture_object *t = _mesa_lookup_texture(ctx, texture); if (!t) { _mesa_error(ctx, GL_INVALID_VALUE, "glBindImageTexture(texture)"); return; } /* From section 8.22 "Texture Image Loads and Stores" of the OpenGL ES * 3.1 spec: * * "An INVALID_OPERATION error is generated if texture is not the name * of an immutable texture object." */ if (_mesa_is_gles(ctx) && !t->Immutable) { _mesa_error(ctx, GL_INVALID_OPERATION, "glBindImageTexture(!immutable)"); return; } _mesa_reference_texobj(&u->TexObj, t); } else { _mesa_reference_texobj(&u->TexObj, NULL); } u->Level = level; u->Access = access; u->Format = format; u->_ActualFormat = _mesa_get_shader_image_format(format); if (u->TexObj && _mesa_tex_target_is_layered(u->TexObj->Target)) { u->Layered = layered; u->Layer = layer; u->_Layer = (u->Layered ? 0 : u->Layer); } else { u->Layered = GL_FALSE; u->Layer = 0; } if (ctx->Driver.BindImageTexture) ctx->Driver.BindImageTexture(ctx, u, u->TexObj, level, layered, layer, access, format); }
/** * See if textures are loaded in texture memory. * * \param n number of textures to query. * \param texName array with the texture names. * \param residences array which will hold the residence status. * * \return GL_TRUE if all textures are resident and \p residences is left unchanged, * * Note: we assume all textures are always resident */ GLboolean GLAPIENTRY _mesa_AreTexturesResident(GLsizei n, const GLuint *texName, GLboolean *residences) { GET_CURRENT_CONTEXT(ctx); GLboolean allResident = GL_TRUE; GLint i; ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); if (n < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident(n)"); return GL_FALSE; } if (!texName || !residences) return GL_FALSE; /* We only do error checking on the texture names */ for (i = 0; i < n; i++) { struct gl_texture_object *t; if (texName[i] == 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident"); return GL_FALSE; } t = _mesa_lookup_texture(ctx, texName[i]); if (!t) { _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident"); return GL_FALSE; } } return allResident; }
/* This function makes a texture view without bothering with all of the API * checks. Most of them are the same for CopyTexSubImage so checking would * be redundant. The one major difference is that we don't check for * whether the texture is immutable or not. However, since the view will * be created and then immediately destroyed, this should not be a problem. */ static bool make_view(struct gl_context *ctx, struct gl_texture_image *tex_image, struct gl_texture_image **view_tex_image, GLuint *view_tex_name, GLenum internal_format) { struct gl_texture_object *tex_obj = tex_image->TexObject; struct gl_texture_object *view_tex_obj; mesa_format tex_format; /* Set up the new texture object */ _mesa_GenTextures(1, view_tex_name); view_tex_obj = _mesa_lookup_texture(ctx, *view_tex_name); if (!view_tex_obj) return false; tex_format = _mesa_choose_texture_format(ctx, view_tex_obj, tex_obj->Target, 0, internal_format, GL_NONE, GL_NONE); if (!ctx->Driver.TestProxyTexImage(ctx, tex_obj->Target, 0, tex_format, tex_image->Width, tex_image->Height, tex_image->Depth, 0)) { _mesa_DeleteTextures(1, view_tex_name); *view_tex_name = 0; return false; } view_tex_obj->Target = tex_obj->Target; *view_tex_image = _mesa_get_tex_image(ctx, view_tex_obj, tex_obj->Target, 0); if (!*view_tex_image) { _mesa_DeleteTextures(1, view_tex_name); *view_tex_name = 0; return false; } _mesa_init_teximage_fields(ctx, *view_tex_image, tex_image->Width, tex_image->Height, tex_image->Depth, 0, internal_format, tex_format); view_tex_obj->MinLevel = tex_image->Level; view_tex_obj->NumLevels = 1; view_tex_obj->MinLayer = tex_obj->MinLayer; view_tex_obj->NumLayers = tex_obj->NumLayers; view_tex_obj->Immutable = tex_obj->Immutable; view_tex_obj->ImmutableLevels = tex_obj->ImmutableLevels; view_tex_obj->Target = tex_obj->Target; if (ctx->Driver.TextureView != NULL && !ctx->Driver.TextureView(ctx, view_tex_obj, tex_obj)) { _mesa_DeleteTextures(1, view_tex_name); *view_tex_name = 0; return false; /* driver recorded error */ } return true; }
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; }
/** * Delete named textures. * * \param n number of textures to be deleted. * \param textures array of texture IDs to be deleted. * * \sa glDeleteTextures(). * * If we're about to delete a texture that's currently bound to any * texture unit, unbind the texture first. Decrement the reference * count on the texture object and delete it if it's zero. * Recall that texture objects can be shared among several rendering * contexts. */ void GLAPIENTRY _mesa_DeleteTextures( GLsizei n, const GLuint *textures) { GET_CURRENT_CONTEXT(ctx); GLint i; if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) _mesa_debug(ctx, "glDeleteTextures %d\n", n); FLUSH_VERTICES(ctx, 0); /* too complex */ if (!textures) return; for (i = 0; i < n; i++) { if (textures[i] > 0) { struct gl_texture_object *delObj = _mesa_lookup_texture(ctx, textures[i]); if (delObj) { _mesa_lock_texture(ctx, delObj); /* Check if texture is bound to any framebuffer objects. * If so, unbind. * See section 4.4.2.3 of GL_EXT_framebuffer_object. */ unbind_texobj_from_fbo(ctx, delObj); /* Check if this texture is currently bound to any texture units. * If so, unbind it. */ unbind_texobj_from_texunits(ctx, delObj); _mesa_unlock_texture(ctx, delObj); ctx->NewState |= _NEW_TEXTURE; /* The texture _name_ is now free for re-use. * Remove it from the hash table now. */ _glthread_LOCK_MUTEX(ctx->Shared->Mutex); _mesa_HashRemove(ctx->Shared->TexObjects, delObj->Name); _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); /* Unreference the texobj. If refcount hits zero, the texture * will be deleted. */ _mesa_reference_texobj(&delObj, NULL); } } } }
static struct gl_texture_object * invalidate_tex_image_error_check(struct gl_context *ctx, GLuint texture, GLint level, const char *name) { /* The GL_ARB_invalidate_subdata spec says: * * "If <texture> is zero or is not the name of a texture, the error * INVALID_VALUE is generated." * * This performs the error check in a different order than listed in the * spec. We have to get the texture object before we can validate the * other parameters against values in the texture object. */ struct gl_texture_object *const t = _mesa_lookup_texture(ctx, texture); if (texture == 0 || t == NULL) { _mesa_error(ctx, GL_INVALID_VALUE, "%s(texture)", name); return NULL; } /* The GL_ARB_invalidate_subdata spec says: * * "If <level> is less than zero or greater than the base 2 logarithm * of the maximum texture width, height, or depth, the error * INVALID_VALUE is generated." */ if (level < 0 || level > t->MaxLevel) { _mesa_error(ctx, GL_INVALID_VALUE, "%s(level)", name); return NULL; } /* The GL_ARB_invalidate_subdata spec says: * * "If the target of <texture> is TEXTURE_RECTANGLE, TEXTURE_BUFFER, * TEXTURE_2D_MULTISAMPLE, or TEXTURE_2D_MULTISAMPLE_ARRAY, and <level> * is not zero, the error INVALID_VALUE is generated." */ if (level != 0) { switch (t->Target) { case GL_TEXTURE_RECTANGLE: case GL_TEXTURE_BUFFER: case GL_TEXTURE_2D_MULTISAMPLE: case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: _mesa_error(ctx, GL_INVALID_VALUE, "%s(level)", name); return NULL; default: break; } } return t; }
void GLAPIENTRY _mesa_BindImageTexture(GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format) { GET_CURRENT_CONTEXT(ctx); struct gl_texture_object *t = NULL; struct gl_image_unit *u; if (!validate_bind_image_texture(ctx, unit, texture, level, layered, layer, access, format)) return; u = &ctx->ImageUnits[unit]; FLUSH_VERTICES(ctx, 0); ctx->NewDriverState |= ctx->DriverFlags.NewImageUnits; if (texture) { t = _mesa_lookup_texture(ctx, texture); if (!t) { _mesa_error(ctx, GL_INVALID_VALUE, "glBindImageTexture(texture)"); return; } _mesa_reference_texobj(&u->TexObj, t); u->Level = level; u->Access = access; u->Format = format; u->_ActualFormat = get_image_format(format); if (_mesa_tex_target_is_layered(t->Target)) { u->Layered = layered; u->Layer = (layered ? 0 : layer); } else { u->Layered = GL_FALSE; u->Layer = 0; } } else { _mesa_reference_texobj(&u->TexObj, NULL); } u->_Valid = validate_image_unit(ctx, u); if (ctx->Driver.BindImageTexture) ctx->Driver.BindImageTexture(ctx, u, t, level, layered, layer, access, format); }
/** * See if a name corresponds to a texture. * * \param texture texture name. * * \return GL_TRUE if texture name corresponds to a texture, or GL_FALSE * otherwise. * * \sa glIsTexture(). * * Calls _mesa_HashLookup(). */ GLboolean GLAPIENTRY _mesa_IsTexture( GLuint texture ) { struct gl_texture_object *t; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); if (!texture) return GL_FALSE; t = _mesa_lookup_texture(ctx, texture); /* IsTexture is true only after object has been bound once. */ return t && t->Target; }
void r300SetTexOffset(__DRIcontext * pDRICtx, GLint texname, unsigned long long offset, GLint depth, GLuint pitch) { r300ContextPtr rmesa = pDRICtx->driverPrivate; struct gl_texture_object *tObj = _mesa_lookup_texture(rmesa->radeon.glCtx, texname); radeonTexObjPtr t = radeon_tex_obj(tObj); uint32_t pitch_val; if (!tObj) return; t->image_override = GL_TRUE; if (!offset) return; t->bo = NULL; t->override_offset = offset; t->pp_txpitch &= (1 << 13) -1; pitch_val = pitch; switch (depth) { case 32: t->pp_txformat = R300_EASY_TX_FORMAT(X, Y, Z, W, W8Z8Y8X8); t->pp_txfilter |= tx_table[2].filter; pitch_val /= 4; break; case 24: default: t->pp_txformat = R300_EASY_TX_FORMAT(X, Y, Z, ONE, W8Z8Y8X8); t->pp_txfilter |= tx_table[4].filter; pitch_val /= 4; break; case 16: t->pp_txformat = R300_EASY_TX_FORMAT(X, Y, Z, ONE, Z5Y6X5); t->pp_txfilter |= tx_table[5].filter; pitch_val /= 2; break; } pitch_val--; t->pp_txpitch |= pitch_val; }
/** * Delete named textures. * * \param n number of textures to be deleted. * \param textures array of texture IDs to be deleted. * * \sa glDeleteTextures(). * * If we're about to delete a texture that's currently bound to any * texture unit, unbind the texture first. Decrement the reference * count on the texture object and delete it if it's zero. * Recall that texture objects can be shared among several rendering * contexts. */ void GLAPIENTRY _mesa_DeleteTextures( GLsizei n, const GLuint *textures) { GET_CURRENT_CONTEXT(ctx); GLint i; ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); /* too complex */ if (!textures) return; for (i = 0; i < n; i++) { if (textures[i] > 0) { struct gl_texture_object *delObj = _mesa_lookup_texture(ctx, textures[i]); if (delObj) { _mesa_lock_texture(ctx, delObj); /* Check if this texture is currently bound to any texture units. * If so, unbind it. */ unbind_texobj_from_texunits(ctx, delObj); _mesa_unlock_texture(ctx, delObj); ctx->NewState |= _NEW_TEXTURE; /* The texture _name_ is now free for re-use. * Remove it from the hash table now. */ _glthread_LOCK_MUTEX(ctx->Shared->Mutex); _mesa_HashRemove(ctx->Shared->TexObjects, delObj->Name); _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); /* Unreference the texobj. If refcount hits zero, the texture * will be deleted. */ _mesa_reference_texobj(&delObj, NULL); } } } }
void intelSetTexOffset(__DRIcontext *pDRICtx, GLint texname, unsigned long long offset, GLint depth, GLuint pitch) { struct intel_context *intel = (struct intel_context*) ((__DRIcontextPrivate*)pDRICtx->private)->driverPrivate; struct gl_texture_object *tObj = _mesa_lookup_texture(&intel->ctx, texname); struct intel_texture_object *intelObj = intel_texture_object(tObj); if (!intelObj) return; if (intelObj->mt) intel_miptree_release(intel, &intelObj->mt); intelObj->imageOverride = GL_TRUE; intelObj->depthOverride = depth; intelObj->pitchOverride = pitch; if (offset) intelObj->textureOffset = offset; }
/** * Try to do a color or depth glBlitFramebuffer using texturing. * * We can do this when the src renderbuffer is actually a texture, or when the * driver exposes BindRenderbufferTexImage(). */ static bool blitframebuffer_texture(struct gl_context *ctx, const struct gl_framebuffer *readFb, const struct gl_framebuffer *drawFb, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLenum filter, GLint flipX, GLint flipY, GLboolean glsl_version, GLboolean do_depth) { int att_index = do_depth ? BUFFER_DEPTH : readFb->_ColorReadBufferIndex; const struct gl_renderbuffer_attachment *readAtt = &readFb->Attachment[att_index]; struct blit_state *blit = &ctx->Meta->Blit; struct fb_tex_blit_state fb_tex_blit; const GLint dstX = MIN2(dstX0, dstX1); const GLint dstY = MIN2(dstY0, dstY1); const GLint dstW = abs(dstX1 - dstX0); const GLint dstH = abs(dstY1 - dstY0); const int srcW = abs(srcX1 - srcX0); const int srcH = abs(srcY1 - srcY0); bool scaled_blit = false; struct gl_texture_object *texObj; GLuint srcLevel; GLenum target; struct gl_renderbuffer *rb = readAtt->Renderbuffer; struct temp_texture *meta_temp_texture; if (rb->NumSamples && !ctx->Extensions.ARB_texture_multisample) return false; _mesa_meta_fb_tex_blit_begin(ctx, &fb_tex_blit); if (readAtt->Texture && (readAtt->Texture->Target == GL_TEXTURE_2D || readAtt->Texture->Target == GL_TEXTURE_RECTANGLE || readAtt->Texture->Target == GL_TEXTURE_2D_MULTISAMPLE || readAtt->Texture->Target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY)) { /* If there's a texture attached of a type we can handle, then just use * it directly. */ srcLevel = readAtt->TextureLevel; texObj = readAtt->Texture; target = texObj->Target; } else if (!readAtt->Texture && ctx->Driver.BindRenderbufferTexImage) { if (!_mesa_meta_bind_rb_as_tex_image(ctx, rb, &fb_tex_blit.tempTex, &texObj, &target)) return false; srcLevel = 0; if (_mesa_is_winsys_fbo(readFb)) { GLint temp = srcY0; srcY0 = rb->Height - srcY1; srcY1 = rb->Height - temp; flipY = -flipY; } } else { GLenum tex_base_format; /* Fall back to doing a CopyTexSubImage to get the destination * renderbuffer into a texture. */ if (ctx->Meta->Blit.no_ctsi_fallback) return false; if (rb->NumSamples > 1) return false; if (do_depth) { meta_temp_texture = _mesa_meta_get_temp_depth_texture(ctx); tex_base_format = GL_DEPTH_COMPONENT; } else { meta_temp_texture = _mesa_meta_get_temp_texture(ctx); tex_base_format = _mesa_base_tex_format(ctx, rb->InternalFormat); } srcLevel = 0; target = meta_temp_texture->Target; texObj = _mesa_lookup_texture(ctx, meta_temp_texture->TexObj); if (texObj == NULL) { return false; } _mesa_meta_setup_copypix_texture(ctx, meta_temp_texture, srcX0, srcY0, srcW, srcH, tex_base_format, filter); srcX0 = 0; srcY0 = 0; srcX1 = srcW; srcY1 = srcH; } fb_tex_blit.baseLevelSave = texObj->BaseLevel; fb_tex_blit.maxLevelSave = texObj->MaxLevel; fb_tex_blit.stencilSamplingSave = texObj->StencilSampling; scaled_blit = dstW != srcW || dstH != srcH; if (glsl_version) { setup_glsl_blit_framebuffer(ctx, blit, drawFb, rb, target, filter, scaled_blit, do_depth); } else { _mesa_meta_setup_ff_tnl_for_blit(ctx, &ctx->Meta->Blit.VAO, &ctx->Meta->Blit.buf_obj, 2); } /* printf("Blit from texture!\n"); printf(" srcAtt %p dstAtt %p\n", readAtt, drawAtt); printf(" srcTex %p dstText %p\n", texObj, drawAtt->Texture); */ fb_tex_blit.sampler = _mesa_meta_setup_sampler(ctx, texObj, target, filter, srcLevel); /* Always do our blits with no net sRGB decode or encode. * * However, if both the src and dst can be srgb decode/encoded, enable them * so that we do any blending (from scaling or from MSAA resolves) in the * right colorspace. * * Our choice of not doing any net encode/decode is from the GL 3.0 * specification: * * "Blit operations bypass the fragment pipeline. The only fragment * operations which affect a blit are the pixel ownership test and the * scissor test." * * The GL 4.4 specification disagrees and says that the sRGB part of the * fragment pipeline applies, but this was found to break applications. */ if (ctx->Extensions.EXT_texture_sRGB_decode) { if (_mesa_get_format_color_encoding(rb->Format) == GL_SRGB && drawFb->Visual.sRGBCapable) { _mesa_SamplerParameteri(fb_tex_blit.sampler, GL_TEXTURE_SRGB_DECODE_EXT, GL_DECODE_EXT); _mesa_set_framebuffer_srgb(ctx, GL_TRUE); } else { _mesa_SamplerParameteri(fb_tex_blit.sampler, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT); /* set_framebuffer_srgb was set by _mesa_meta_begin(). */ } } if (!glsl_version) { _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); _mesa_set_enable(ctx, target, GL_TRUE); } /* Prepare vertex data (the VBO was previously created and bound) */ { struct vertex verts[4]; GLfloat s0, t0, s1, t1; if (target == GL_TEXTURE_2D) { const struct gl_texture_image *texImage = _mesa_select_tex_image(texObj, target, srcLevel); s0 = srcX0 / (float) texImage->Width; s1 = srcX1 / (float) texImage->Width; t0 = srcY0 / (float) texImage->Height; t1 = srcY1 / (float) texImage->Height; } else { assert(target == GL_TEXTURE_RECTANGLE_ARB || target == GL_TEXTURE_2D_MULTISAMPLE || target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY); s0 = (float) srcX0; s1 = (float) srcX1; t0 = (float) srcY0; t1 = (float) srcY1; } /* Silence valgrind warnings about reading uninitialized stack. */ memset(verts, 0, sizeof(verts)); /* setup vertex positions */ verts[0].x = -1.0F * flipX; verts[0].y = -1.0F * flipY; verts[1].x = 1.0F * flipX; verts[1].y = -1.0F * flipY; verts[2].x = 1.0F * flipX; verts[2].y = 1.0F * flipY; verts[3].x = -1.0F * flipX; verts[3].y = 1.0F * flipY; verts[0].tex[0] = s0; verts[0].tex[1] = t0; verts[0].tex[2] = readAtt->Zoffset; verts[1].tex[0] = s1; verts[1].tex[1] = t0; verts[1].tex[2] = readAtt->Zoffset; verts[2].tex[0] = s1; verts[2].tex[1] = t1; verts[2].tex[2] = readAtt->Zoffset; verts[3].tex[0] = s0; verts[3].tex[1] = t1; verts[3].tex[2] = readAtt->Zoffset; _mesa_buffer_sub_data(ctx, blit->buf_obj, 0, sizeof(verts), verts, __func__); } /* setup viewport */ _mesa_set_viewport(ctx, 0, dstX, dstY, dstW, dstH); _mesa_ColorMask(!do_depth, !do_depth, !do_depth, !do_depth); _mesa_set_enable(ctx, GL_DEPTH_TEST, do_depth); _mesa_DepthMask(do_depth); _mesa_DepthFunc(GL_ALWAYS); _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); _mesa_meta_fb_tex_blit_end(ctx, target, &fb_tex_blit); return true; }
/** * Bind a named texture to a texturing target. * * \param target texture target. * \param texName texture name. * * \sa glBindTexture(). * * Determines the old texture object bound and returns immediately if rebinding * the same texture. Get the current texture which is either a default texture * if name is null, a named texture from the hash, or a new texture if the * given texture name is new. Increments its reference count, binds it, and * calls dd_function_table::BindTexture. Decrements the old texture reference * count and deletes it if it reaches zero. */ void GLAPIENTRY _mesa_BindTexture( GLenum target, GLuint texName ) { GET_CURRENT_CONTEXT(ctx); struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx); struct gl_texture_object *newTexObj = NULL; GLint targetIndex; ASSERT_OUTSIDE_BEGIN_END(ctx); if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) _mesa_debug(ctx, "glBindTexture %s %d\n", _mesa_lookup_enum_by_nr(target), (GLint) texName); targetIndex = target_enum_to_index(ctx, target); if (targetIndex < 0) { _mesa_error(ctx, GL_INVALID_ENUM, "glBindTexture(target)"); return; } assert(targetIndex < NUM_TEXTURE_TARGETS); /* * Get pointer to new texture object (newTexObj) */ if (texName == 0) { /* Use a default texture object */ newTexObj = ctx->Shared->DefaultTex[targetIndex]; } else { /* non-default texture object */ newTexObj = _mesa_lookup_texture(ctx, texName); if (newTexObj) { /* error checking */ if (newTexObj->Target != 0 && newTexObj->Target != target) { /* the named texture object's target doesn't match the given target */ _mesa_error( ctx, GL_INVALID_OPERATION, "glBindTexture(target mismatch)" ); return; } if (newTexObj->Target == 0) { finish_texture_init(ctx, target, newTexObj); } } else { if (ctx->API == API_OPENGL_CORE) { _mesa_error(ctx, GL_INVALID_OPERATION, "glBindTexture"); return; } /* if this is a new texture id, allocate a texture object now */ newTexObj = ctx->Driver.NewTextureObject(ctx, texName, target); if (!newTexObj) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindTexture"); return; } /* and insert it into hash table */ _glthread_LOCK_MUTEX(ctx->Shared->Mutex); _mesa_HashInsert(ctx->Shared->TexObjects, texName, newTexObj); _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); } newTexObj->Target = target; } assert(valid_texture_object(newTexObj)); /* Check if this texture is only used by this context and is already bound. * If so, just return. */ { GLboolean early_out; _glthread_LOCK_MUTEX(ctx->Shared->Mutex); early_out = ((ctx->Shared->RefCount == 1) && (newTexObj == texUnit->CurrentTex[targetIndex])); _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); if (early_out) { return; } } /* flush before changing binding */ FLUSH_VERTICES(ctx, _NEW_TEXTURE); /* Do the actual binding. The refcount on the previously bound * texture object will be decremented. It'll be deleted if the * count hits zero. */ _mesa_reference_texobj(&texUnit->CurrentTex[targetIndex], newTexObj); ASSERT(texUnit->CurrentTex[targetIndex]); /* Pass BindTexture call to device driver */ if (ctx->Driver.BindTexture) ctx->Driver.BindTexture(ctx, target, newTexObj); }
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; }
static GLintptr register_surface(struct gl_context *ctx, GLboolean isOutput, const GLvoid *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames) { struct vdp_surface *surf; int i; if (!ctx->vdpDevice || !ctx->vdpGetProcAddress || !ctx->vdpSurfaces) { _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAURegisterSurfaceNV"); return (GLintptr)NULL; } if (target != GL_TEXTURE_2D && target != GL_TEXTURE_RECTANGLE) { _mesa_error(ctx, GL_INVALID_ENUM, "VDPAURegisterSurfaceNV"); return (GLintptr)NULL; } if (target == GL_TEXTURE_RECTANGLE && !ctx->Extensions.NV_texture_rectangle) { _mesa_error(ctx, GL_INVALID_ENUM, "VDPAURegisterSurfaceNV"); return (GLintptr)NULL; } surf = CALLOC_STRUCT( vdp_surface ); if (surf == NULL) { _mesa_error_no_memory("VDPAURegisterSurfaceNV"); return (GLintptr)NULL; } surf->vdpSurface = vdpSurface; surf->target = target; surf->access = GL_READ_WRITE; surf->state = GL_SURFACE_REGISTERED_NV; surf->output = isOutput; for (i = 0; i < numTextureNames; ++i) { struct gl_texture_object *tex; tex = _mesa_lookup_texture(ctx, textureNames[i]); if (tex == NULL) { free(surf); _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAURegisterSurfaceNV(texture ID not found)"); return (GLintptr)NULL; } _mesa_lock_texture(ctx, tex); if (tex->Immutable) { _mesa_unlock_texture(ctx, tex); free(surf); _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAURegisterSurfaceNV(texture is immutable)"); return (GLintptr)NULL; } if (tex->Target == 0) tex->Target = target; else if (tex->Target != target) { _mesa_unlock_texture(ctx, tex); free(surf); _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAURegisterSurfaceNV(target mismatch)"); return (GLintptr)NULL; } /* This will disallow respecifying the storage. */ tex->Immutable = GL_TRUE; _mesa_unlock_texture(ctx, tex); _mesa_reference_texobj(&surf->textures[i], tex); } _mesa_set_add(ctx->vdpSurfaces, surf); return (GLintptr)surf; }
/** * 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 struct gl_texture_image * create_texture_for_pbo(struct gl_context *ctx, bool create_pbo, GLenum pbo_target, int width, int height, GLenum format, GLenum type, const void *pixels, const struct gl_pixelstore_attrib *packing, GLuint *tmp_pbo, GLuint *tmp_tex) { uint32_t pbo_format; GLenum internal_format; unsigned row_stride; struct gl_buffer_object *buffer_obj; struct gl_texture_object *tex_obj; struct gl_texture_image *tex_image; bool read_only; if (packing->SwapBytes || packing->LsbFirst || packing->Invert) return NULL; pbo_format = _mesa_format_from_format_and_type(format, type); if (_mesa_format_is_mesa_array_format(pbo_format)) pbo_format = _mesa_format_from_array_format(pbo_format); if (!pbo_format || !ctx->TextureFormatSupported[pbo_format]) return NULL; /* Account for SKIP_PIXELS, SKIP_ROWS, ALIGNMENT, and SKIP_IMAGES */ pixels = _mesa_image_address3d(packing, pixels, width, height, format, type, 0, 0, 0); row_stride = _mesa_image_row_stride(packing, width, format, type); if (_mesa_is_bufferobj(packing->BufferObj)) { *tmp_pbo = 0; buffer_obj = packing->BufferObj; } else { bool is_pixel_pack = pbo_target == GL_PIXEL_PACK_BUFFER; assert(create_pbo); _mesa_GenBuffers(1, tmp_pbo); /* We are not doing this inside meta_begin/end. However, we know the * client doesn't have the given target bound, so we can go ahead and * squash it. We'll set it back when we're done. */ _mesa_BindBuffer(pbo_target, *tmp_pbo); /* In case of GL_PIXEL_PACK_BUFFER, pass null pointer for the pixel * data to avoid unnecessary data copying in _mesa_BufferData(). */ if (is_pixel_pack) _mesa_BufferData(pbo_target, row_stride * height, NULL, GL_STREAM_READ); else _mesa_BufferData(pbo_target, row_stride * height, pixels, GL_STREAM_DRAW); buffer_obj = packing->BufferObj; pixels = NULL; _mesa_BindBuffer(pbo_target, 0); } _mesa_GenTextures(1, tmp_tex); tex_obj = _mesa_lookup_texture(ctx, *tmp_tex); _mesa_initialize_texture_object(ctx, tex_obj, *tmp_tex, GL_TEXTURE_2D); /* This must be set after _mesa_initialize_texture_object, not before. */ tex_obj->Immutable = GL_TRUE; /* This is required for interactions with ARB_texture_view. */ tex_obj->NumLayers = 1; internal_format = _mesa_get_format_base_format(pbo_format); tex_image = _mesa_get_tex_image(ctx, tex_obj, tex_obj->Target, 0); _mesa_init_teximage_fields(ctx, tex_image, width, height, 1, 0, internal_format, pbo_format); read_only = pbo_target == GL_PIXEL_UNPACK_BUFFER; if (!ctx->Driver.SetTextureStorageForBufferObject(ctx, tex_obj, buffer_obj, (intptr_t)pixels, row_stride, read_only)) { _mesa_DeleteTextures(1, tmp_tex); _mesa_DeleteBuffers(1, tmp_pbo); return NULL; } return tex_image; }
static struct gl_texture_image * create_texture_for_pbo(struct gl_context *ctx, bool create_pbo, GLenum pbo_target, int dims, int width, int height, int depth, GLenum format, GLenum type, const void *pixels, const struct gl_pixelstore_attrib *packing, struct gl_buffer_object **tmp_pbo, GLuint *tmp_tex) { uint32_t pbo_format; GLenum internal_format; unsigned row_stride; struct gl_buffer_object *buffer_obj; struct gl_texture_object *tex_obj; struct gl_texture_image *tex_image; bool read_only; if (packing->SwapBytes || packing->LsbFirst || packing->Invert) return NULL; pbo_format = _mesa_format_from_format_and_type(format, type); if (_mesa_format_is_mesa_array_format(pbo_format)) pbo_format = _mesa_format_from_array_format(pbo_format); if (!pbo_format || !ctx->TextureFormatSupported[pbo_format]) return NULL; /* Account for SKIP_PIXELS, SKIP_ROWS, ALIGNMENT, and SKIP_IMAGES */ uint32_t first_pixel = _mesa_image_offset(dims, packing, width, height, format, type, 0, 0, 0); uint32_t last_pixel = _mesa_image_offset(dims, packing, width, height, format, type, depth-1, height-1, width); row_stride = _mesa_image_row_stride(packing, width, format, type); if (_mesa_is_bufferobj(packing->BufferObj)) { *tmp_pbo = NULL; buffer_obj = packing->BufferObj; first_pixel += (intptr_t)pixels; } else { bool is_pixel_pack = pbo_target == GL_PIXEL_PACK_BUFFER; assert(create_pbo); *tmp_pbo = ctx->Driver.NewBufferObject(ctx, 0xDEADBEEF); if (*tmp_pbo == NULL) return NULL; /* In case of GL_PIXEL_PACK_BUFFER, pass null pointer for the pixel * data to avoid unnecessary data copying in _mesa_buffer_data. */ if (is_pixel_pack) _mesa_buffer_data(ctx, *tmp_pbo, GL_NONE, last_pixel - first_pixel, NULL, GL_STREAM_READ, __func__); else _mesa_buffer_data(ctx, *tmp_pbo, GL_NONE, last_pixel - first_pixel, (char *)pixels + first_pixel, GL_STREAM_DRAW, __func__); buffer_obj = *tmp_pbo; first_pixel = 0; } _mesa_GenTextures(1, tmp_tex); tex_obj = _mesa_lookup_texture(ctx, *tmp_tex); _mesa_initialize_texture_object(ctx, tex_obj, *tmp_tex, GL_TEXTURE_2D); /* This must be set after _mesa_initialize_texture_object, not before. */ tex_obj->Immutable = GL_TRUE; /* This is required for interactions with ARB_texture_view. */ tex_obj->NumLayers = 1; internal_format = _mesa_get_format_base_format(pbo_format); /* The texture is addressed as a single very-tall image, so we * need to pack the multiple image depths together taking the * inter-image padding into account. */ int image_height = packing->ImageHeight == 0 ? height : packing->ImageHeight; int full_height = image_height * (depth - 1) + height; tex_image = _mesa_get_tex_image(ctx, tex_obj, tex_obj->Target, 0); _mesa_init_teximage_fields(ctx, tex_image, width, full_height, 1, 0, internal_format, pbo_format); read_only = pbo_target == GL_PIXEL_UNPACK_BUFFER; if (!ctx->Driver.SetTextureStorageForBufferObject(ctx, tex_obj, buffer_obj, first_pixel, row_stride, read_only)) { _mesa_DeleteTextures(1, tmp_tex); _mesa_reference_buffer_object(ctx, tmp_pbo, NULL); return NULL; } return tex_image; }
/** * Common code called by glFramebufferTexture1D/2D/3DEXT(). */ static void framebuffer_texture(GLcontext *ctx, const char *caller, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset) { struct gl_renderbuffer_attachment *att; struct gl_texture_object *texObj = NULL; struct gl_framebuffer *fb; ASSERT_OUTSIDE_BEGIN_END(ctx); if (target != GL_FRAMEBUFFER_EXT) { _mesa_error(ctx, GL_INVALID_ENUM, "glFramebufferTexture%sEXT(target)", caller); return; } fb = ctx->DrawBuffer; ASSERT(fb); /* check framebuffer binding */ if (fb->Name == 0) { _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferTexture%sEXT", caller); return; } /* The textarget, level, and zoffset parameters are only validated if * texture is non-zero. */ if (texture) { GLboolean err = GL_TRUE; texObj = _mesa_lookup_texture(ctx, texture); if (texObj != NULL) { if (textarget == 0) { err = (texObj->Target != GL_TEXTURE_3D) && (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT) && (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT); } else { err = (texObj->Target == GL_TEXTURE_CUBE_MAP) ? !IS_CUBE_FACE(textarget) : (texObj->Target != textarget); } } if (err) { _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferTexture%sEXT(texture target mismatch)", caller); return; } if (texObj->Target == GL_TEXTURE_3D) { const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1); if (zoffset < 0 || zoffset >= maxSize) { _mesa_error(ctx, GL_INVALID_VALUE, "glFramebufferTexture%sEXT(zoffset)", caller); return; } } else if ((texObj->Target == GL_TEXTURE_1D_ARRAY_EXT) || (texObj->Target == GL_TEXTURE_2D_ARRAY_EXT)) { if (zoffset < 0 || zoffset >= ctx->Const.MaxArrayTextureLayers) { _mesa_error(ctx, GL_INVALID_VALUE, "glFramebufferTexture%sEXT(layer)", caller); return; } } if ((level < 0) || (level >= _mesa_max_texture_levels(ctx, texObj->Target))) { _mesa_error(ctx, GL_INVALID_VALUE, "glFramebufferTexture%sEXT(level)", caller); return; } } att = _mesa_get_attachment(ctx, fb, attachment); if (att == NULL) { _mesa_error(ctx, GL_INVALID_ENUM, "glFramebufferTexture%sEXT(attachment)", caller); return; } FLUSH_VERTICES(ctx, _NEW_BUFFERS); /* The above doesn't fully flush the drivers in the way that a * glFlush does, but that is required here: */ if (ctx->Driver.Flush) ctx->Driver.Flush(ctx); _glthread_LOCK_MUTEX(fb->Mutex); if (texObj) { _mesa_set_texture_attachment(ctx, fb, att, texObj, textarget, level, zoffset); } else { _mesa_remove_attachment(ctx, att); } _glthread_UNLOCK_MUTEX(fb->Mutex); }
/** * glTextureView (ARB_texture_view) * If an error is found, record it with _mesa_error() * \return none. */ void GLAPIENTRY _mesa_TextureView(GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers) { struct gl_texture_object *texObj; struct gl_texture_object *origTexObj; struct gl_texture_image *origTexImage; GLuint newViewMinLevel, newViewMinLayer; GLuint newViewNumLevels, newViewNumLayers; GLsizei width, height, depth; mesa_format texFormat; GLboolean sizeOK, dimensionsOK; GLenum faceTarget; GET_CURRENT_CONTEXT(ctx); if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) _mesa_debug(ctx, "glTextureView %d %s %d %s %d %d %d %d\n", texture, _mesa_lookup_enum_by_nr(target), origtexture, _mesa_lookup_enum_by_nr(internalformat), minlevel, numlevels, minlayer, numlayers); if (origtexture == 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glTextureView(origtexture = %u)", origtexture); return; } /* Need original texture information to validate arguments */ origTexObj = _mesa_lookup_texture(ctx, origtexture); /* If <origtexture> is not the name of a texture, INVALID_VALUE is generated. */ if (!origTexObj) { _mesa_error(ctx, GL_INVALID_VALUE, "glTextureView(origtexture = %u)", origtexture); return; } /* If <origtexture>'s TEXTURE_IMMUTABLE_FORMAT value is not TRUE, * INVALID_OPERATION is generated. */ if (!origTexObj->Immutable) { _mesa_error(ctx, GL_INVALID_OPERATION, "glTextureView(origtexture not immutable)"); return; } /* If <texture> is 0, INVALID_VALUE is generated. */ if (texture == 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glTextureView(texture = 0)"); return; } /* If <texture> is not a valid name returned by GenTextures, * the error INVALID_OPERATION is generated. */ texObj = _mesa_lookup_texture(ctx, texture); if (texObj == NULL) { _mesa_error(ctx, GL_INVALID_OPERATION, "glTextureView(texture = %u non-gen name)", texture); return; } /* If <texture> has already been bound and given a target, then * the error INVALID_OPERATION is generated. */ if (texObj->Target) { _mesa_error(ctx, GL_INVALID_OPERATION, "glTextureView(texture = %u already bound)", texture); return; } /* Check for compatible target */ if (!target_valid(ctx, origTexObj->Target, target)) { return; /* error was recorded */ } /* minlevel and minlayer are relative to the view of origtexture * If minlevel or minlayer is greater than level or layer, respectively, * of origtexture return INVALID_VALUE. */ newViewMinLevel = origTexObj->MinLevel + minlevel; newViewMinLayer = origTexObj->MinLayer + minlayer; if (newViewMinLevel >= (origTexObj->MinLevel + origTexObj->NumLevels)) { _mesa_error(ctx, GL_INVALID_VALUE, "glTextureView(new minlevel (%d) > orig minlevel (%d) + orig numlevels (%d))", newViewMinLevel, origTexObj->MinLevel, origTexObj->NumLevels); return; } if (newViewMinLayer >= (origTexObj->MinLayer + origTexObj->NumLayers)) { _mesa_error(ctx, GL_INVALID_VALUE, "glTextureView(new minlayer (%d) > orig minlayer (%d) + orig numlayers (%d))", newViewMinLayer, origTexObj->MinLayer, origTexObj->NumLayers); return; } if (!_mesa_texture_view_compatible_format(ctx, origTexObj->Image[0][0]->InternalFormat, internalformat)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glTextureView(internalformat %s not compatible with origtexture %s)", _mesa_lookup_enum_by_nr(internalformat), _mesa_lookup_enum_by_nr(origTexObj->Image[0][0]->InternalFormat)); return; } texFormat = _mesa_choose_texture_format(ctx, texObj, target, 0, internalformat, GL_NONE, GL_NONE); assert(texFormat != MESA_FORMAT_NONE); if (texFormat == MESA_FORMAT_NONE) return; newViewNumLevels = MIN2(numlevels, origTexObj->NumLevels - minlevel); newViewNumLayers = MIN2(numlayers, origTexObj->NumLayers - minlayer); faceTarget = origTexObj->Target; if (faceTarget == GL_TEXTURE_CUBE_MAP) faceTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + minlayer; /* Get a reference to what will become this View's base level */ origTexImage = _mesa_select_tex_image(origTexObj, faceTarget, minlevel); width = origTexImage->Width; height = origTexImage->Height; depth = origTexImage->Depth; /* Adjust width, height, depth to be appropriate for new target */ switch (target) { case GL_TEXTURE_1D: height = 1; break; case GL_TEXTURE_3D: break; case GL_TEXTURE_1D_ARRAY: height = (GLsizei) newViewNumLayers; break; case GL_TEXTURE_2D: case GL_TEXTURE_2D_MULTISAMPLE: case GL_TEXTURE_RECTANGLE: case GL_TEXTURE_CUBE_MAP: depth = 1; break; case GL_TEXTURE_2D_ARRAY: case GL_TEXTURE_CUBE_MAP_ARRAY: case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: depth = newViewNumLayers; break; } /* If the dimensions of the original texture are larger than the maximum * supported dimensions of the new target, the error INVALID_OPERATION is * generated. For example, if the original texture has a TEXTURE_2D_ARRAY * target and its width is greater than MAX_CUBE_MAP_TEXTURE_SIZE, an error * will be generated if TextureView is called to create a TEXTURE_CUBE_MAP * view. */ dimensionsOK = _mesa_legal_texture_dimensions(ctx, target, 0, width, height, depth, 0); if (!dimensionsOK) { _mesa_error(ctx, GL_INVALID_OPERATION, "glTextureView(invalid width or height or depth)"); return; } sizeOK = ctx->Driver.TestProxyTexImage(ctx, target, 0, texFormat, width, height, depth, 0); if (!sizeOK) { _mesa_error(ctx, GL_INVALID_OPERATION, "glTextureView(invalid texture size)"); return; } /* If <target> is TEXTURE_1D, TEXTURE_2D, TEXTURE_3D, TEXTURE_RECTANGLE, * or TEXTURE_2D_MULTISAMPLE and <numlayers> does not equal 1, the error * INVALID_VALUE is generated. */ switch (target) { case GL_TEXTURE_1D: case GL_TEXTURE_2D: case GL_TEXTURE_3D: case GL_TEXTURE_RECTANGLE: case GL_TEXTURE_2D_MULTISAMPLE: if (numlayers != 1) { _mesa_error(ctx, GL_INVALID_VALUE, "glTextureView(numlayers %d != 1)", numlayers); return; } break; case GL_TEXTURE_CUBE_MAP: /* If the new texture's target is TEXTURE_CUBE_MAP, the clamped <numlayers> * must be equal to 6. */ if (newViewNumLayers != 6) { _mesa_error(ctx, GL_INVALID_VALUE, "glTextureView(clamped numlayers %d != 6)", newViewNumLayers); return; } break; case GL_TEXTURE_CUBE_MAP_ARRAY: /* If the new texture's target is TEXTURE_CUBE_MAP_ARRAY, * then <numlayers> counts layer-faces rather than layers, * and the clamped <numlayers> must be a multiple of 6. * Otherwise, the error INVALID_VALUE is generated. */ if ((newViewNumLayers % 6) != 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glTextureView(clamped numlayers %d is not a multiple of 6)", newViewNumLayers); return; } break; } /* If the new texture's target is TEXTURE_CUBE_MAP or * TEXTURE_CUBE_MAP_ARRAY, the width and height of the original texture's * levels must be equal otherwise the error INVALID_OPERATION is generated. */ if ((target == GL_TEXTURE_CUBE_MAP || target == GL_TEXTURE_CUBE_MAP_ARRAY) && (origTexImage->Width != origTexImage->Height)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glTextureView(origtexture width (%d) != height (%d))", origTexImage->Width, origTexImage->Height); return; } /* When the original texture's target is TEXTURE_CUBE_MAP, the layer * parameters are interpreted in the same order as if it were a * TEXTURE_CUBE_MAP_ARRAY with 6 layer-faces. */ /* If the internal format does not exactly match the internal format of the * original texture, the contents of the memory are reinterpreted in the * same manner as for image bindings described in * section 3.9.20 (Texture Image Loads and Stores). */ /* TEXTURE_BASE_LEVEL and TEXTURE_MAX_LEVEL are interpreted * relative to the view and not relative to the original data store. */ if (!initialize_texture_fields(ctx, target, texObj, newViewNumLevels, width, height, depth, internalformat, texFormat)) { return; /* Already recorded error */ } texObj->MinLevel = newViewMinLevel; texObj->MinLayer = newViewMinLayer; texObj->NumLevels = newViewNumLevels; texObj->NumLayers = newViewNumLayers; texObj->Immutable = GL_TRUE; texObj->ImmutableLevels = origTexObj->ImmutableLevels; texObj->Target = target; if (ctx->Driver.TextureView != NULL && !ctx->Driver.TextureView(ctx, texObj, origTexObj)) { return; /* driver recorded error */ } }
/** * 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; }