X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fswrast%2Fs_texture.c;h=9ccd0e34702ea6c5cdd1d33f6367aaa8f67d6677;hb=fbebd5e4a5ccb44ae005a8be18c85ea45c66307f;hp=184fd952dc5f81e367dbdca1cdfefc18e0f545f5;hpb=1da896803cdd09293c7bb0048a2116e237a51766;p=mesa.git diff --git a/src/mesa/swrast/s_texture.c b/src/mesa/swrast/s_texture.c index 184fd952dc5..9ccd0e34702 100644 --- a/src/mesa/swrast/s_texture.c +++ b/src/mesa/swrast/s_texture.c @@ -16,9 +16,10 @@ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. */ /** @@ -29,6 +30,7 @@ #include "main/context.h" #include "main/fbobject.h" #include "main/teximage.h" +#include "main/texobj.h" #include "swrast/swrast.h" #include "swrast/s_context.h" @@ -57,13 +59,126 @@ _swrast_delete_texture_image(struct gl_context *ctx, _mesa_delete_texture_image(ctx, texImage); } +static unsigned int +texture_slices(struct gl_texture_image *texImage) +{ + if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY) + return texImage->Height; + else + return texImage->Depth; +} + +unsigned int +_swrast_teximage_slice_height(struct gl_texture_image *texImage) +{ + /* For 1D array textures, the slices are all 1 pixel high, and Height is + * the number of slices. + */ + if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY) + return 1; + else + return texImage->Height; +} + +/** + * Called via ctx->Driver.AllocTextureImageBuffer() + */ +GLboolean +_swrast_alloc_texture_image_buffer(struct gl_context *ctx, + struct gl_texture_image *texImage) +{ + struct swrast_texture_image *swImg = swrast_texture_image(texImage); + GLuint bytesPerSlice; + GLuint slices = texture_slices(texImage); + GLuint i; + + if (!_swrast_init_texture_image(texImage)) + return GL_FALSE; + + bytesPerSlice = _mesa_format_image_size(texImage->TexFormat, texImage->Width, + _swrast_teximage_slice_height(texImage), 1); + + assert(!swImg->Buffer); + swImg->Buffer = _mesa_align_malloc(bytesPerSlice * slices, 512); + if (!swImg->Buffer) + return GL_FALSE; + + /* RowStride and ImageSlices[] describe how to address texels in 'Data' */ + swImg->RowStride = _mesa_format_row_stride(texImage->TexFormat, + texImage->Width); + + for (i = 0; i < slices; i++) { + swImg->ImageSlices[i] = swImg->Buffer + bytesPerSlice * i; + } + + return GL_TRUE; +} + + +/** + * Code that overrides ctx->Driver.AllocTextureImageBuffer may use this to + * initialize the fields of swrast_texture_image without allocating the image + * buffer or initializing RowStride or the contents of ImageSlices. + * + * Returns GL_TRUE on success, GL_FALSE on memory allocation failure. + */ +GLboolean +_swrast_init_texture_image(struct gl_texture_image *texImage) +{ + struct swrast_texture_image *swImg = swrast_texture_image(texImage); + + if ((texImage->Width == 1 || _mesa_is_pow_two(texImage->Width2)) && + (texImage->Height == 1 || _mesa_is_pow_two(texImage->Height2)) && + (texImage->Depth == 1 || _mesa_is_pow_two(texImage->Depth2))) + swImg->_IsPowerOfTwo = GL_TRUE; + else + swImg->_IsPowerOfTwo = GL_FALSE; + + /* Compute Width/Height/DepthScale for mipmap lod computation */ + if (texImage->TexObject->Target == GL_TEXTURE_RECTANGLE_NV) { + /* scale = 1.0 since texture coords directly map to texels */ + swImg->WidthScale = 1.0; + swImg->HeightScale = 1.0; + swImg->DepthScale = 1.0; + } + else { + swImg->WidthScale = (GLfloat) texImage->Width; + swImg->HeightScale = (GLfloat) texImage->Height; + swImg->DepthScale = (GLfloat) texImage->Depth; + } + + assert(!swImg->ImageSlices); + swImg->ImageSlices = calloc(texture_slices(texImage), sizeof(void *)); + if (!swImg->ImageSlices) + return GL_FALSE; + + return GL_TRUE; +} + + +/** + * Called via ctx->Driver.FreeTextureImageBuffer() + */ +void +_swrast_free_texture_image_buffer(struct gl_context *ctx, + struct gl_texture_image *texImage) +{ + struct swrast_texture_image *swImage = swrast_texture_image(texImage); + + _mesa_align_free(swImage->Buffer); + swImage->Buffer = NULL; + + free(swImage->ImageSlices); + swImage->ImageSlices = NULL; +} + /** * Error checking for debugging only. */ static void -_mesa_check_map_teximage(struct gl_texture_image *texImage, - GLuint slice, GLuint x, GLuint y, GLuint w, GLuint h) +check_map_teximage(const struct gl_texture_image *texImage, + GLuint slice, GLuint x, GLuint y, GLuint w, GLuint h) { if (texImage->TexObject->Target == GL_TEXTURE_1D) @@ -96,29 +211,37 @@ _swrast_map_teximage(struct gl_context *ctx, GLubyte **mapOut, GLint *rowStrideOut) { + struct swrast_texture_image *swImage = swrast_texture_image(texImage); GLubyte *map; GLint stride, texelSize; GLuint bw, bh; - _mesa_check_map_teximage(texImage, slice, x, y, w, h); + check_map_teximage(texImage, slice, x, y, w, h); + + if (!swImage->Buffer) { + /* Either glTexImage was called with a NULL argument or + * we ran out of memory when allocating texture memory, + */ + *mapOut = NULL; + *rowStrideOut = 0; + return; + } texelSize = _mesa_get_format_bytes(texImage->TexFormat); stride = _mesa_format_row_stride(texImage->TexFormat, texImage->Width); _mesa_get_format_block_size(texImage->TexFormat, &bw, &bh); - assert(texImage->Data); + assert(x % bw == 0); + assert(y % bh == 0); - map = texImage->Data; + /* This function can only be used with a swrast-allocated buffer, in which + * case ImageSlices is populated with pointers into Buffer. + */ + assert(swImage->Buffer); + assert(swImage->Buffer == swImage->ImageSlices[0]); - if (texImage->TexObject->Target == GL_TEXTURE_3D || - texImage->TexObject->Target == GL_TEXTURE_2D_ARRAY) { - GLuint sliceSize = _mesa_format_image_size(texImage->TexFormat, - texImage->Width, - texImage->Height, - 1); - assert(slice < texImage->Depth); - map += slice * sliceSize; - } + assert(slice < texture_slices(texImage)); + map = swImage->ImageSlices[slice]; /* apply x/y offset to map address */ map += stride * (y / bh) + texelSize * (x / bw); @@ -134,3 +257,130 @@ _swrast_unmap_teximage(struct gl_context *ctx, { /* nop */ } + + +void +_swrast_map_texture(struct gl_context *ctx, struct gl_texture_object *texObj) +{ + const GLuint faces = _mesa_num_tex_faces(texObj->Target); + GLuint face, level; + + for (face = 0; face < faces; face++) { + for (level = texObj->BaseLevel; level < MAX_TEXTURE_LEVELS; level++) { + struct gl_texture_image *texImage = texObj->Image[face][level]; + struct swrast_texture_image *swImage = swrast_texture_image(texImage); + unsigned int i, slices; + + if (!texImage) + continue; + + /* In the case of a swrast-allocated texture buffer, the ImageSlices + * and RowStride are always available. + */ + if (swImage->Buffer) { + assert(swImage->ImageSlices[0] == swImage->Buffer); + continue; + } + + if (!swImage->ImageSlices) { + swImage->ImageSlices = + calloc(texture_slices(texImage), sizeof(void *)); + if (!swImage->ImageSlices) + continue; + } + + slices = texture_slices(texImage); + + for (i = 0; i < slices; i++) { + GLubyte *map; + GLint rowStride; + + if (swImage->ImageSlices[i]) + continue; + + ctx->Driver.MapTextureImage(ctx, texImage, i, + 0, 0, + texImage->Width, texImage->Height, + GL_MAP_READ_BIT | GL_MAP_WRITE_BIT, + &map, &rowStride); + + swImage->ImageSlices[i] = map; + /* A swrast-using driver has to return the same rowstride for + * every slice of the same texture, since we don't track them + * separately. + */ + if (i == 0) + swImage->RowStride = rowStride; + else + assert(swImage->RowStride == rowStride); + } + } + } +} + + +void +_swrast_unmap_texture(struct gl_context *ctx, struct gl_texture_object *texObj) +{ + const GLuint faces = _mesa_num_tex_faces(texObj->Target); + GLuint face, level; + + for (face = 0; face < faces; face++) { + for (level = texObj->BaseLevel; level < MAX_TEXTURE_LEVELS; level++) { + struct gl_texture_image *texImage = texObj->Image[face][level]; + struct swrast_texture_image *swImage = swrast_texture_image(texImage); + unsigned int i, slices; + + if (!texImage) + continue; + + if (swImage->Buffer) + return; + + if (!swImage->ImageSlices) + continue; + + slices = texture_slices(texImage); + + for (i = 0; i < slices; i++) { + if (swImage->ImageSlices[i]) { + ctx->Driver.UnmapTextureImage(ctx, texImage, i); + swImage->ImageSlices[i] = NULL; + } + } + } + } +} + + +/** + * Map all textures for reading prior to software rendering. + */ +void +_swrast_map_textures(struct gl_context *ctx) +{ + int unit; + + for (unit = 0; unit <= ctx->Texture._MaxEnabledTexImageUnit; unit++) { + struct gl_texture_object *texObj = ctx->Texture.Unit[unit]._Current; + + if (texObj) + _swrast_map_texture(ctx, texObj); + } +} + + +/** + * Unmap all textures for reading prior to software rendering. + */ +void +_swrast_unmap_textures(struct gl_context *ctx) +{ + int unit; + for (unit = 0; unit <= ctx->Texture._MaxEnabledTexImageUnit; unit++) { + struct gl_texture_object *texObj = ctx->Texture.Unit[unit]._Current; + + if (texObj) + _swrast_unmap_texture(ctx, texObj); + } +}