* 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
- * BRIAN PAUL 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.
*/
#include "image.h"
#include "imports.h"
#include "macros.h"
-#include "mfeatures.h"
+#include "multisample.h"
#include "state.h"
#include "texcompress.h"
#include "texcompress_cpal.h"
#include "teximage.h"
#include "texobj.h"
#include "texstate.h"
+#include "texstorage.h"
#include "mtypes.h"
#include "glformats.h"
default:
; /* fallthrough */
}
-
+
if (ctx->Extensions.TDFX_texture_compression_FXT1) {
switch (internalFormat) {
case GL_COMPRESSED_RGB_FXT1_3DFX:
case GL_SRGB_EXT:
case GL_SRGB8_EXT:
case GL_COMPRESSED_SRGB_EXT:
- case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
return GL_RGB;
+ case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
+ return ctx->Extensions.EXT_texture_compression_s3tc ? GL_RGB : -1;
case GL_SRGB_ALPHA_EXT:
case GL_SRGB8_ALPHA8_EXT:
case GL_COMPRESSED_SRGB_ALPHA_EXT:
+ return GL_RGBA;
case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
- return GL_RGBA;
+ return ctx->Extensions.EXT_texture_compression_s3tc ? GL_RGBA : -1;
case GL_SLUMINANCE_ALPHA_EXT:
case GL_SLUMINANCE8_ALPHA8_EXT:
case GL_COMPRESSED_SLUMINANCE_ALPHA_EXT:
/**
* Allocate a texture image structure.
- *
+ *
* Called via ctx->Driver.NewTextureImage() unless overriden by a device
* driver.
*
ctx->Extensions.ARB_texture_buffer_object ?
texUnit->CurrentTex[TEXTURE_BUFFER_INDEX] : NULL;
case GL_TEXTURE_EXTERNAL_OES:
- return ctx->Extensions.OES_EGL_image_external
+ return _mesa_is_gles(ctx) && ctx->Extensions.OES_EGL_image_external
? texUnit->CurrentTex[TEXTURE_EXTERNAL_INDEX] : NULL;
case GL_TEXTURE_2D_MULTISAMPLE:
return ctx->Extensions.ARB_texture_multisample
if (!texObj)
return NULL;
-
+
texImage = _mesa_select_tex_image(ctx, texObj, target, level);
if (!texImage) {
texImage = ctx->Driver.NewTextureImage(ctx);
*
* \param ctx GL context.
* \param target texture target.
- *
+ *
* \return the maximum number of allowed mipmap levels for the given
* texture target, or zero if passed a bad target.
*
switch (target) {
case GL_TEXTURE_1D:
case GL_TEXTURE_1D_ARRAY:
+ case GL_PROXY_TEXTURE_1D:
+ case GL_PROXY_TEXTURE_1D_ARRAY:
size = width;
break;
case GL_TEXTURE_CUBE_MAP:
case GL_TEXTURE_CUBE_MAP_ARRAY:
+ case GL_PROXY_TEXTURE_CUBE_MAP:
+ case GL_PROXY_TEXTURE_CUBE_MAP_ARRAY:
ASSERT(width == height);
size = width;
break;
case GL_TEXTURE_2D:
case GL_TEXTURE_2D_ARRAY:
+ case GL_PROXY_TEXTURE_2D:
+ case GL_PROXY_TEXTURE_2D_ARRAY:
size = MAX2(width, height);
break;
case GL_TEXTURE_3D:
+ case GL_PROXY_TEXTURE_3D:
size = MAX3(width, height, depth);
break;
case GL_TEXTURE_RECTANGLE:
case GL_TEXTURE_EXTERNAL_OES:
case GL_TEXTURE_2D_MULTISAMPLE:
case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
+ case GL_PROXY_TEXTURE_RECTANGLE:
+ case GL_PROXY_TEXTURE_2D_MULTISAMPLE:
+ case GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY:
return 1;
default:
assert(0);
}
/* check xoffset and width */
- if (xoffset < -destImage->Border) {
+ if (xoffset < - (GLint) destImage->Border) {
_mesa_error(ctx, GL_INVALID_VALUE, "%s%dD(xoffset)",
function, dims);
return GL_TRUE;
}
- if (xoffset + subWidth > destImage->Width) {
+ if (xoffset + subWidth > (GLint) destImage->Width) {
_mesa_error(ctx, GL_INVALID_VALUE, "%s%dD(xoffset+width)",
function, dims);
return GL_TRUE;
function, dims);
return GL_TRUE;
}
- if (yoffset + subHeight > destImage->Height) {
+ if (yoffset + subHeight > (GLint) destImage->Height) {
_mesa_error(ctx, GL_INVALID_VALUE, "%s%dD(yoffset+height)",
function, dims);
return GL_TRUE;
return GL_TRUE;
}
- /* size must be multiple of bw by bh or equal to whole texture size */
- if ((subWidth % bw != 0) && subWidth != destImage->Width) {
+ /* The size must be a multiple of bw x bh, or we must be using a
+ * offset+size that exactly hits the edge of the image. This
+ * is important for small mipmap levels (1x1, 2x1, etc) and for
+ * NPOT textures.
+ */
+ if ((subWidth % bw != 0) &&
+ (xoffset + subWidth != (GLint) destImage->Width)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"%s%dD(width = %d)", function, dims, subWidth);
return GL_TRUE;
}
- if ((subHeight % bh != 0) && subHeight != destImage->Height) {
+ if ((subHeight % bh != 0) &&
+ (yoffset + subHeight != (GLint) destImage->Height)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"%s%dD(height = %d)", function, dims, subHeight);
return GL_TRUE;
- }
+ }
}
return GL_FALSE;
return ctx->Extensions.ARB_texture_cube_map_array;
default:
return GL_FALSE;
- }
+ }
}
static GLboolean
mutable_tex_object(struct gl_context *ctx, GLenum target)
{
- if (ctx->Extensions.ARB_texture_storage) {
- struct gl_texture_object *texObj =
- _mesa_get_current_tex_object(ctx, target);
- return !texObj->Immutable;
- }
- return GL_TRUE;
+ struct gl_texture_object *texObj = _mesa_get_current_tex_object(ctx, target);
+ return !texObj->Immutable;
}
/**
* Test the glTexImage[123]D() parameters for errors.
- *
+ *
* \param ctx GL context.
* \param dimensions texture image dimensions (must be 1, 2 or 3).
* \param target texture target given by the user (already validated).
* \param height image height given by the user.
* \param depth image depth given by the user.
* \param border image border given by the user.
- *
+ *
* \return GL_TRUE if a error is found, GL_FALSE otherwise
*
* Verifies each of the parameters against the constants specified in
internalFormat);
} else {
if (format != internalFormat) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glTexImage%dD(format = %s, internalFormat = %s)",
- dimensions,
- _mesa_lookup_enum_by_nr(format),
- _mesa_lookup_enum_by_nr(internalFormat));
- return GL_TRUE;
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glTexImage%dD(format = %s, internalFormat = %s)",
+ dimensions,
+ _mesa_lookup_enum_by_nr(format),
+ _mesa_lookup_enum_by_nr(internalFormat));
+ return GL_TRUE;
}
err = _mesa_es_error_check_format_and_type(format, type, dimensions);
/**
* Test glTexSubImage[123]D() parameters for errors.
- *
+ *
* \param ctx GL context.
* \param dimensions texture image dimensions (must be 1, 2 or 3).
* \param target texture target given by the user (already validated)
* \param width image width given by the user.
* \param height image height given by the user.
* \param depth image depth given by the user.
- *
+ *
* \return GL_TRUE if an error was detected, or GL_FALSE if no errors.
*
* Verifies each of the parameters against the constants specified in
/**
* Test glCopyTexImage[12]D() parameters for errors.
- *
+ *
* \param ctx GL context.
* \param dimensions texture image dimensions (must be 1, 2 or 3).
* \param target texture target given by the user.
* \param width image width given by the user.
* \param height image height given by the user.
* \param border texture border.
- *
+ *
* \return GL_TRUE if an error was detected, or GL_FALSE if no errors.
- *
+ *
* Verifies each of the parameters against the constants specified in
* __struct gl_contextRec::Const and the supported extensions, and according
* to the OpenGL specification.
_mesa_error(ctx, GL_INVALID_ENUM, "glCopyTexImage%uD(target=%s)",
dimensions, _mesa_lookup_enum_by_nr(target));
return GL_TRUE;
- }
+ }
/* level check */
if (level < 0 || level >= _mesa_max_texture_levels(ctx, target)) {
att->Texture == texObj &&
att->TextureLevel == level &&
att->CubeMapFace == face) {
- ASSERT(_mesa_get_attachment_teximage(att));
- /* Tell driver about the new renderbuffer texture */
- ctx->Driver.RenderTexture(ctx, ctx->DrawBuffer, att);
+ _mesa_update_texture_renderbuffer(ctx, ctx->DrawBuffer, att);
+ ASSERT(att->Renderbuffer->TexImage);
/* Mark fb status as indeterminate to force re-validation */
fb->_Status = 0;
}
return f;
}
+
/**
* Adjust pixel unpack params and image dimensions to strip off the
* one-pixel texture border.
*height = *height - 2; /* reduce the height by two border pixels */
}
- if (*depth >= 3 && target != GL_TEXTURE_2D_ARRAY && target != GL_TEXTURE_CUBE_MAP_ARRAY) {
+ if (*depth >= 3 &&
+ target != GL_TEXTURE_2D_ARRAY &&
+ target != GL_TEXTURE_CUBE_MAP_ARRAY) {
unpackNew->SkipImages++; /* skip the border */
*depth = *depth - 2; /* reduce the depth by two border pixels */
}
valid_target = ctx->Extensions.OES_EGL_image;
break;
case GL_TEXTURE_EXTERNAL_OES:
- valid_target = ctx->Extensions.OES_EGL_image_external;
+ valid_target =
+ _mesa_is_gles(ctx) ? ctx->Extensions.OES_EGL_image_external : false;
break;
default:
valid_target = false;
_mesa_error(ctx, GL_INVALID_ENUM, "glTexSubImage%uD(target=%s)",
dims, _mesa_lookup_enum_by_nr(target));
return;
- }
+ }
if (ctx->NewState & _NEW_PIXEL)
_mesa_update_state(ctx);
}
}
+static void
+copytexsubimage_by_slice(struct gl_context *ctx,
+ struct gl_texture_image *texImage,
+ GLuint dims,
+ GLint xoffset, GLint yoffset, GLint zoffset,
+ struct gl_renderbuffer *rb,
+ GLint x, GLint y,
+ GLsizei width, GLsizei height)
+{
+ if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY) {
+ int slice;
+
+ /* For 1D arrays, we copy each scanline of the source rectangle into the
+ * next array slice.
+ */
+ assert(zoffset == 0);
+
+ for (slice = 0; slice < height; slice++) {
+ assert(yoffset + slice < texImage->Height);
+ ctx->Driver.CopyTexSubImage(ctx, 2, texImage,
+ xoffset, 0, yoffset + slice,
+ rb, x, y + slice, width, 1);
+ }
+ } else {
+ ctx->Driver.CopyTexSubImage(ctx, dims, texImage,
+ xoffset, yoffset, zoffset,
+ rb, x, y, width, height);
+ }
+}
/**
struct gl_renderbuffer *srcRb =
get_copy_tex_image_source(ctx, texImage->TexFormat);
- ctx->Driver.CopyTexSubImage(ctx, dims, texImage, dstX, dstY, dstZ,
- srcRb, srcX, srcY, width, height);
+ copytexsubimage_by_slice(ctx, texImage, dims,
+ dstX, dstY, dstZ,
+ srcRb, srcX, srcY, width, height);
}
check_gen_mipmap(ctx, target, texObj, level);
struct gl_renderbuffer *srcRb =
get_copy_tex_image_source(ctx, texImage->TexFormat);
- ctx->Driver.CopyTexSubImage(ctx, dims, texImage,
- xoffset, yoffset, zoffset,
- srcRb, x, y, width, height);
+ copytexsubimage_by_slice(ctx, texImage, dims,
+ xoffset, yoffset, zoffset,
+ srcRb, x, y, width, height);
check_gen_mipmap(ctx, target, texObj, level);
targetOK = GL_FALSE;
break;
}
-
+
if (!targetOK) {
_mesa_error(ctx, GL_INVALID_ENUM, "glCompressedTexImage%uD(target)",
dims);
}
}
+
static gl_format
validate_texbuffer_format(const struct gl_context *ctx, GLenum internalFormat)
{
_mesa_unlock_texture(ctx, texObj);
}
+
/** GL_ARB_texture_buffer_object */
void GLAPIENTRY
_mesa_TexBuffer(GLenum target, GLenum internalFormat, GLuint buffer)
texbufferrange(ctx, target, internalFormat, bufObj, 0, buffer ? -1 : 0);
}
+
/** GL_ARB_texture_buffer_range */
void GLAPIENTRY
_mesa_TexBufferRange(GLenum target, GLenum internalFormat, GLuint buffer,
texbufferrange(ctx, target, internalFormat, bufObj, offset, size);
}
+
static GLboolean
is_renderable_texture_format(struct gl_context *ctx, GLenum internalformat)
{
return baseFormat != 0 && baseFormat != GL_STENCIL_INDEX;
}
+
/** GL_ARB_texture_multisample */
static GLboolean
check_multisample_target(GLuint dims, GLenum target)
}
}
+
static void
teximagemultisample(GLuint dims, GLenum target, GLsizei samples,
GLint internalformat, GLsizei width, GLsizei height,
- GLsizei depth, GLboolean fixedsamplelocations)
+ GLsizei depth, GLboolean fixedsamplelocations,
+ GLboolean immutable, const char *func)
{
struct gl_texture_object *texObj;
struct gl_texture_image *texImage;
GLboolean sizeOK, dimensionsOK;
gl_format texFormat;
+ GLenum sample_count_error;
GET_CURRENT_CONTEXT(ctx);
if (!(ctx->Extensions.ARB_texture_multisample
&& _mesa_is_desktop_gl(ctx))) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glTexImage%uDMultisample", dims);
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unsupported)", func);
return;
}
if (!check_multisample_target(dims, target)) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glTexImage%uDMultisample(target)", dims);
+ _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func);
return;
}
* refer GL3.1 spec 4.4.4
*/
+ if (immutable && !_mesa_is_legal_tex_storage_format(ctx, internalformat)) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "%s(internalformat=%s not legal for immutable-format)",
+ func, _mesa_lookup_enum_by_nr(internalformat));
+ return;
+ }
+
if (!is_renderable_texture_format(ctx, internalformat)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
- "glTexImage%uDMultisample(internalformat=%s)",
- dims,
- _mesa_lookup_enum_by_nr(internalformat));
+ "%s(internalformat=%s)",
+ func, _mesa_lookup_enum_by_nr(internalformat));
return;
}
- if (_mesa_is_enum_format_integer(internalformat)) {
- if (samples > ctx->Const.MaxIntegerSamples) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glTexImage%uDMultisample(samples>GL_MAX_INTEGER_SAMPLES)",
- dims);
- return;
- }
- }
- else if (_mesa_is_depth_or_stencil_format(internalformat)) {
- if (samples > ctx->Const.MaxDepthTextureSamples) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glTexImage%uDMultisample(samples>GL_MAX_DEPTH_TEXTURE_SAMPLES)",
- dims);
- return;
- }
- }
- else {
- if (samples > ctx->Const.MaxColorTextureSamples) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glTexImage%uDMultisample(samples>GL_MAX_COLOR_TEXTURE_SAMPLES)",
- dims);
- return;
- }
+ sample_count_error = _mesa_check_sample_count(ctx, target,
+ internalformat, samples);
+ if (sample_count_error != GL_NO_ERROR) {
+ _mesa_error(ctx, sample_count_error, "%s(samples)", func);
+ return;
}
- /* TODO: should ask the driver for the exact limit for this internalformat
- * once IDR's internalformat_query bits land
- */
-
texObj = _mesa_get_current_tex_object(ctx, target);
+
+ if (immutable && (!texObj || (texObj->Name == 0))) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(texture object 0)",
+ func);
+ return;
+ }
+
texImage = _mesa_get_tex_image(ctx, texObj, 0, 0);
if (texImage == NULL) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage%uDMultisample()", dims);
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s()", func);
return;
}
else {
if (!dimensionsOK) {
_mesa_error(ctx, GL_INVALID_VALUE,
- "glTexImage%uDMultisample(invalid width or height)", dims);
+ "%s(invalid width or height)", func);
return;
}
if (!sizeOK) {
_mesa_error(ctx, GL_OUT_OF_MEMORY,
- "glTexImage%uDMultisample(texture too large)", dims);
+ "%s(texture too large)", func);
+ return;
+ }
+
+ /* Check if texObj->Immutable is set */
+ if (texObj->Immutable) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s(immutable)", func);
return;
}
texImage->FixedSampleLocations = fixedsamplelocations;
if (width > 0 && height > 0 && depth > 0) {
-
if (!ctx->Driver.AllocTextureStorage(ctx, texObj, 1,
width, height, depth)) {
/* tidy up the texture image state. strictly speaking,
}
}
+ texObj->Immutable = immutable;
_mesa_update_fbo_texture(ctx, texObj, 0, 0);
}
}
+
void GLAPIENTRY
_mesa_TexImage2DMultisample(GLenum target, GLsizei samples,
GLint internalformat, GLsizei width,
GLsizei height, GLboolean fixedsamplelocations)
{
teximagemultisample(2, target, samples, internalformat,
- width, height, 1, fixedsamplelocations);
+ width, height, 1, fixedsamplelocations, GL_FALSE,
+ "glTexImage2DMultisample");
}
+
void GLAPIENTRY
_mesa_TexImage3DMultisample(GLenum target, GLsizei samples,
GLint internalformat, GLsizei width,
GLboolean fixedsamplelocations)
{
teximagemultisample(3, target, samples, internalformat,
- width, height, depth, fixedsamplelocations);
+ width, height, depth, fixedsamplelocations, GL_FALSE,
+ "glTexImage3DMultisample");
+}
+
+
+void GLAPIENTRY
+_mesa_TexStorage2DMultisample(GLenum target, GLsizei samples,
+ GLenum internalformat, GLsizei width,
+ GLsizei height, GLboolean fixedsamplelocations)
+{
+ teximagemultisample(2, target, samples, internalformat,
+ width, height, 1, fixedsamplelocations, GL_TRUE,
+ "glTexStorage2DMultisample");
+}
+
+
+void GLAPIENTRY
+_mesa_TexStorage3DMultisample(GLenum target, GLsizei samples,
+ GLenum internalformat, GLsizei width,
+ GLsizei height, GLsizei depth,
+ GLboolean fixedsamplelocations)
+{
+ teximagemultisample(3, target, samples, internalformat,
+ width, height, depth, fixedsamplelocations, GL_TRUE,
+ "glTexStorage3DMultisample");
}