diff options
Diffstat (limited to 'src/mesa/main')
-rw-r--r-- | src/mesa/main/copyimage.c | 356 | ||||
-rw-r--r-- | src/mesa/main/copyimage.h | 49 | ||||
-rw-r--r-- | src/mesa/main/dd.h | 16 | ||||
-rw-r--r-- | src/mesa/main/extensions.c | 1 | ||||
-rw-r--r-- | src/mesa/main/mtypes.h | 1 | ||||
-rw-r--r-- | src/mesa/main/tests/dispatch_sanity.cpp | 2 | ||||
-rw-r--r-- | src/mesa/main/textureview.c | 36 | ||||
-rw-r--r-- | src/mesa/main/textureview.h | 4 |
8 files changed, 445 insertions, 20 deletions
diff --git a/src/mesa/main/copyimage.c b/src/mesa/main/copyimage.c new file mode 100644 index 00000000000..e1110dd7e00 --- /dev/null +++ b/src/mesa/main/copyimage.c @@ -0,0 +1,356 @@ +/* + * Mesa 3-D graphics library + * + * Copyright (C) 2014 Intel Corporation. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * 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 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. + * + * Authors: + * Jason Ekstrand <[email protected]> + */ + +#include "glheader.h" +#include "errors.h" +#include "enums.h" +#include "copyimage.h" +#include "teximage.h" +#include "texobj.h" +#include "fbobject.h" +#include "textureview.h" + +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) +{ + struct gl_renderbuffer *rb; + + 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) { + 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(ctx, *tex_obj, *target, level); + if (!*tex_image) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyImageSubData(%sLevel = %u)", dbg_prefix, level); + return false; + } + } + + return true; +} + +static bool +check_region_bounds(struct gl_context *ctx, struct gl_texture_image *tex_image, + int x, int y, int z, int width, int height, int depth, + const char *dbg_prefix) +{ + if (width < 0 || height < 0 || depth < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyImageSubData(%sWidth, %sHeight, or %sDepth is negative)", + dbg_prefix, dbg_prefix, dbg_prefix); + return false; + } + + if (x < 0 || y < 0 || z < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyImageSubData(%sX, %sY, or %sZ is negative)", + dbg_prefix, dbg_prefix, dbg_prefix); + return false; + } + + if (x + width > tex_image->Width) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyImageSubData(%sX or %sWidth exceeds image bounds)", + dbg_prefix, dbg_prefix); + return false; + } + + switch (tex_image->TexObject->Target) { + case GL_TEXTURE_1D: + case GL_TEXTURE_1D_ARRAY: + if (y != 0 || height != 1) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyImageSubData(%sY or %sHeight exceeds image bounds)", + dbg_prefix, dbg_prefix); + return false; + } + break; + default: + if (y + height > tex_image->Height) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyImageSubData(%sY or %sHeight exceeds image bounds)", + dbg_prefix, dbg_prefix); + return false; + } + break; + } + + switch (tex_image->TexObject->Target) { + case GL_TEXTURE_1D: + case GL_TEXTURE_2D: + case GL_TEXTURE_2D_MULTISAMPLE: + case GL_TEXTURE_RECTANGLE: + if (z != 0 || depth != 1) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyImageSubData(%sZ or %sDepth exceeds image bounds)", + dbg_prefix, dbg_prefix); + return false; + } + break; + case GL_TEXTURE_CUBE_MAP: + if (z < 0 || z + depth > 6) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyImageSubData(%sZ or %sDepth exceeds image bounds)", + dbg_prefix, dbg_prefix); + return false; + } + break; + case GL_TEXTURE_1D_ARRAY: + if (z < 0 || z + depth > tex_image->Height) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyImageSubData(%sZ or %sDepth exceeds image bounds)", + dbg_prefix, dbg_prefix); + return false; + } + break; + case GL_TEXTURE_CUBE_MAP_ARRAY: + case GL_TEXTURE_2D_ARRAY: + case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: + case GL_TEXTURE_3D: + if (z < 0 || z + depth > tex_image->Depth) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyImageSubData(%sZ or %sDepth exceeds image bounds)", + dbg_prefix, dbg_prefix); + return false; + } + break; + } + + return true; +} + +void +_mesa_CopyImageSubData(GLuint srcName, GLenum srcTarget, GLint srcLevel, + GLint srcX, GLint srcY, GLint srcZ, + GLuint dstName, GLenum dstTarget, GLint dstLevel, + GLint dstX, GLint dstY, GLint dstZ, + GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth) +{ + GET_CURRENT_CONTEXT(ctx); + GLuint tmpTexNames[2] = { 0, 0 }; + struct gl_texture_object *srcTexObj, *dstTexObj; + struct gl_texture_image *srcTexImage, *dstTexImage; + GLuint src_bw, src_bh, dst_bw, dst_bh; + int i, srcNewZ, dstNewZ, Bpt; + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glCopyImageSubData(%u, %s, %d, %d, %d, %d, " + "%u, %s, %d, %d, %d, %d, " + "%d, %d, %d)\n", + srcName, _mesa_lookup_enum_by_nr(srcTarget), srcLevel, + srcX, srcY, srcZ, + dstName, _mesa_lookup_enum_by_nr(dstTarget), dstLevel, + dstX, dstY, dstZ, + srcWidth, srcHeight, srcWidth); + + if (!prepare_target(ctx, srcName, &srcTarget, srcLevel, + &srcTexObj, &srcTexImage, &tmpTexNames[0], "src")) + goto cleanup; + + if (!prepare_target(ctx, dstName, &dstTarget, dstLevel, + &dstTexObj, &dstTexImage, &tmpTexNames[1], "dst")) + goto cleanup; + + _mesa_get_format_block_size(srcTexImage->TexFormat, &src_bw, &src_bh); + if ((srcX % src_bw != 0) || (srcY % src_bh != 0) || + (srcWidth % src_bw != 0) || (srcHeight % src_bh != 0)) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyImageSubData(unaligned src rectangle)"); + goto cleanup; + } + + _mesa_get_format_block_size(dstTexImage->TexFormat, &dst_bw, &dst_bh); + if ((dstX % dst_bw != 0) || (dstY % dst_bh != 0)) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyImageSubData(unaligned dst rectangle)"); + goto cleanup; + } + + /* Very simple sanity check. This is sufficient if one of the textures + * is compressed. */ + Bpt = _mesa_get_format_bytes(srcTexImage->TexFormat); + if (_mesa_get_format_bytes(dstTexImage->TexFormat) != Bpt) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyImageSubData(internalFormat mismatch)"); + goto cleanup; + } + + if (!check_region_bounds(ctx, srcTexImage, srcX, srcY, srcZ, + srcWidth, srcHeight, srcDepth, "src")) + goto cleanup; + + if (!check_region_bounds(ctx, dstTexImage, dstX, dstY, dstZ, + (srcWidth / src_bw) * dst_bw, + (srcHeight / src_bh) * dst_bh, srcDepth, "dst")) + goto cleanup; + + if (_mesa_is_format_compressed(srcTexImage->TexFormat)) { + /* XXX: Technically, we should probaby do some more specific checking + * here. However, this should be sufficient for all compressed + * formats that mesa supports since it is a direct memory copy. + */ + } else if (_mesa_is_format_compressed(dstTexImage->TexFormat)) { + } else if (_mesa_texture_view_compatible_format(ctx, + srcTexImage->InternalFormat, + dstTexImage->InternalFormat)) { + } else { + return; /* Error loged by _mesa_texture_view_compatible_format */ + } + + for (i = 0; i < srcDepth; ++i) { + if (srcTexObj->Target == GL_TEXTURE_CUBE_MAP) { + srcTexImage = srcTexObj->Image[i + srcZ][srcLevel]; + srcNewZ = 0; + } else { + srcNewZ = srcZ + i; + } + + if (dstTexObj->Target == GL_TEXTURE_CUBE_MAP) { + dstTexImage = dstTexObj->Image[i + dstZ][dstLevel]; + dstNewZ = 0; + } else { + dstNewZ = dstZ + i; + } + + ctx->Driver.CopyImageSubData(ctx, srcTexImage, srcX, srcY, srcNewZ, + dstTexImage, dstX, dstY, dstNewZ, + srcWidth, srcHeight); + } + +cleanup: + _mesa_DeleteTextures(2, tmpTexNames); +} diff --git a/src/mesa/main/copyimage.h b/src/mesa/main/copyimage.h new file mode 100644 index 00000000000..40e95b66312 --- /dev/null +++ b/src/mesa/main/copyimage.h @@ -0,0 +1,49 @@ +/* + * Mesa 3-D graphics library + * + * Copyright (C) 2014 Intel Corporation. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * 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 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. + * + * Authors: + * Jason Ekstrand <[email protected]> + */ + + +#ifndef COPYIMAGE_H +#define COPYIMAGE_H + +#include "mtypes.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern void GLAPIENTRY +_mesa_CopyImageSubData(GLuint srcName, GLenum srcTarget, GLint srcLevel, + GLint srcX, GLint srcY, GLint srcZ, + GLuint destName, GLenum destTarget, GLint destLevel, + GLint destX, GLint destY, GLint destZ, + GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth); + +#ifdef __cplusplus +} +#endif + +#endif /* COPYIMAGE_H */ diff --git a/src/mesa/main/dd.h b/src/mesa/main/dd.h index 89765351e14..c130b14a522 100644 --- a/src/mesa/main/dd.h +++ b/src/mesa/main/dd.h @@ -269,6 +269,22 @@ struct dd_function_table { GLsizei width, GLsizei height); /** + * Called by glCopyImageSubData(). + * + * This function should copy one 2-D slice from srcTexImage to + * dstTexImage. If one of the textures is 3-D or is a 1-D or 2-D array + * texture, this function will be called multiple times: once for each + * slice. If one of the textures is a cube map, this function will be + * called once for each face to be copied. + */ + void (*CopyImageSubData)(struct gl_context *ctx, + struct gl_texture_image *src_image, + int src_x, int src_y, int src_z, + struct gl_texture_image *dstTexImage, + int dst_x, int dst_y, int dst_z, + int src_width, int src_height); + + /** * Called by glGenerateMipmap() or when GL_GENERATE_MIPMAP_SGIS is enabled. * Note that if the texture is a cube map, the <target> parameter will * indicate which cube face to generate (GL_POSITIVE/NEGATIVE_X/Y/Z). diff --git a/src/mesa/main/extensions.c b/src/mesa/main/extensions.c index 9ac8377a475..d60838a1ce7 100644 --- a/src/mesa/main/extensions.c +++ b/src/mesa/main/extensions.c @@ -95,6 +95,7 @@ static const struct extension extension_table[] = { { "GL_ARB_compressed_texture_pixel_storage", o(dummy_true), GL, 2011 }, { "GL_ARB_compute_shader", o(ARB_compute_shader), GL, 2012 }, { "GL_ARB_copy_buffer", o(dummy_true), GL, 2008 }, + { "GL_ARB_copy_image", o(ARB_copy_image), GL, 2012 }, { "GL_ARB_conservative_depth", o(ARB_conservative_depth), GL, 2011 }, { "GL_ARB_debug_output", o(dummy_true), GL, 2009 }, { "GL_ARB_depth_buffer_float", o(ARB_depth_buffer_float), GL, 2008 }, diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h index ff130da15d0..e141ac65893 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -3552,6 +3552,7 @@ struct gl_extensions GLboolean ARB_color_buffer_float; GLboolean ARB_compute_shader; GLboolean ARB_conservative_depth; + GLboolean ARB_copy_image; GLboolean ARB_depth_buffer_float; GLboolean ARB_depth_clamp; GLboolean ARB_depth_texture; diff --git a/src/mesa/main/tests/dispatch_sanity.cpp b/src/mesa/main/tests/dispatch_sanity.cpp index 5e751f493ff..04fa86b72db 100644 --- a/src/mesa/main/tests/dispatch_sanity.cpp +++ b/src/mesa/main/tests/dispatch_sanity.cpp @@ -838,7 +838,7 @@ const struct function gl_core_functions_possible[] = { // { "glClearNamedBufferSubDataEXT", 43, -1 }, // XXX: Add to xml { "glDispatchCompute", 43, -1 }, { "glDispatchComputeIndirect", 43, -1 }, -// { "glCopyImageSubData", 43, -1 }, // XXX: Add to xml + { "glCopyImageSubData", 43, -1 }, { "glTextureView", 43, -1 }, { "glBindVertexBuffer", 43, -1 }, { "glVertexAttribFormat", 43, -1 }, diff --git a/src/mesa/main/textureview.c b/src/mesa/main/textureview.c index 77a3b782b5a..b3521e2190e 100644 --- a/src/mesa/main/textureview.c +++ b/src/mesa/main/textureview.c @@ -320,15 +320,11 @@ target_valid(struct gl_context *ctx, GLenum origTarget, GLenum newTarget) * If an error is found, record it with _mesa_error() * \return false if any error, true otherwise. */ -static bool -compatible_format(struct gl_context *ctx, const struct gl_texture_object *origTexObj, - GLenum internalformat) +GLboolean +_mesa_texture_view_compatible_format(struct gl_context *ctx, + GLenum origInternalFormat, + GLenum newInternalFormat) { - /* Level 0 of a texture created by glTextureStorage or glTextureView - * is always defined. - */ - struct gl_texture_image *texImage = origTexObj->Image[0][0]; - GLint origInternalFormat = texImage->InternalFormat; unsigned int origViewClass, newViewClass; /* The two textures' internal formats must be compatible according to @@ -337,19 +333,15 @@ compatible_format(struct gl_context *ctx, const struct gl_texture_object *origTe * The internal formats must be identical if not in that table, * or an INVALID_OPERATION error is generated. */ - if (origInternalFormat == internalformat) - return true; + if (origInternalFormat == newInternalFormat) + return GL_TRUE; origViewClass = lookup_view_class(ctx, origInternalFormat); - newViewClass = lookup_view_class(ctx, internalformat); + newViewClass = lookup_view_class(ctx, newInternalFormat); if ((origViewClass == newViewClass) && origViewClass != false) - return true; + return GL_TRUE; - _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(origInternalFormat)); - return false; + return GL_FALSE; } /** * Helper function for TexStorage and teximagemultisample to set immutable @@ -512,8 +504,14 @@ _mesa_TextureView(GLuint texture, GLenum target, GLuint origtexture, return; } - if (!compatible_format(ctx, origTexObj, internalformat)) { - return; /* Error logged */ + 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, diff --git a/src/mesa/main/textureview.h b/src/mesa/main/textureview.h index 3088ac19393..549a13cd809 100644 --- a/src/mesa/main/textureview.h +++ b/src/mesa/main/textureview.h @@ -29,6 +29,10 @@ #ifndef TEXTUREVIEW_H #define TEXTUREVIEW_H +GLboolean +_mesa_texture_view_compatible_format(struct gl_context *ctx, + GLenum origInternalFormat, + GLenum newInternalFormat); extern void GLAPIENTRY _mesa_TextureView(GLuint texture, GLenum target, GLuint origtexture, |