gecko-dev/dom/canvas/WebGL2ContextTextures.cpp

217 lines
7.5 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "WebGL2Context.h"
#include "GLContext.h"
using namespace mozilla;
using namespace mozilla::dom;
bool
WebGL2Context::ValidateSizedInternalFormat(GLenum internalformat, const char* info)
{
switch (internalformat) {
// Sized Internal Formats
// https://www.khronos.org/opengles/sdk/docs/man3/html/glTexStorage2D.xhtml
case LOCAL_GL_R8:
case LOCAL_GL_R8_SNORM:
case LOCAL_GL_R16F:
case LOCAL_GL_R32F:
case LOCAL_GL_R8UI:
case LOCAL_GL_R8I:
case LOCAL_GL_R16UI:
case LOCAL_GL_R16I:
case LOCAL_GL_R32UI:
case LOCAL_GL_R32I:
case LOCAL_GL_RG8:
case LOCAL_GL_RG8_SNORM:
case LOCAL_GL_RG16F:
case LOCAL_GL_RG32F:
case LOCAL_GL_RG8UI:
case LOCAL_GL_RG8I:
case LOCAL_GL_RG16UI:
case LOCAL_GL_RG16I:
case LOCAL_GL_RG32UI:
case LOCAL_GL_RG32I:
case LOCAL_GL_RGB8:
case LOCAL_GL_SRGB8:
case LOCAL_GL_RGB565:
case LOCAL_GL_RGB8_SNORM:
case LOCAL_GL_R11F_G11F_B10F:
case LOCAL_GL_RGB9_E5:
case LOCAL_GL_RGB16F:
case LOCAL_GL_RGB32F:
case LOCAL_GL_RGB8UI:
case LOCAL_GL_RGB8I:
case LOCAL_GL_RGB16UI:
case LOCAL_GL_RGB16I:
case LOCAL_GL_RGB32UI:
case LOCAL_GL_RGB32I:
case LOCAL_GL_RGBA8:
case LOCAL_GL_SRGB8_ALPHA8:
case LOCAL_GL_RGBA8_SNORM:
case LOCAL_GL_RGB5_A1:
case LOCAL_GL_RGBA4:
case LOCAL_GL_RGB10_A2:
case LOCAL_GL_RGBA16F:
case LOCAL_GL_RGBA32F:
case LOCAL_GL_RGBA8UI:
case LOCAL_GL_RGBA8I:
case LOCAL_GL_RGB10_A2UI:
case LOCAL_GL_RGBA16UI:
case LOCAL_GL_RGBA16I:
case LOCAL_GL_RGBA32I:
case LOCAL_GL_RGBA32UI:
case LOCAL_GL_DEPTH_COMPONENT16:
case LOCAL_GL_DEPTH_COMPONENT24:
case LOCAL_GL_DEPTH_COMPONENT32F:
case LOCAL_GL_DEPTH24_STENCIL8:
case LOCAL_GL_DEPTH32F_STENCIL8:
return true;
}
if (IsCompressedTextureFormat(internalformat)) {
return true;
}
const char* name = EnumName(internalformat);
if (name && name[0] != '[')
ErrorInvalidEnum("%s: invalid internal format %s", info, name);
else
ErrorInvalidEnum("%s: invalid internal format 0x%04X", info, internalformat);
return false;
}
/** Validates parameters to texStorage{2D,3D} */
bool
WebGL2Context::ValidateTexStorage(GLenum target, GLsizei levels, GLenum internalformat,
GLsizei width, GLsizei height, GLsizei depth,
const char* info)
{
// GL_INVALID_OPERATION is generated if the default texture object is curently bound to target.
WebGLTexture* tex = activeBoundTextureForTarget(target);
if (!tex) {
ErrorInvalidOperation("%s: no texture is bound to target %s", info, EnumName(target));
return false;
}
// GL_INVALID_OPERATION is generated if the texture object currently bound to target already has
// GL_TEXTURE_IMMUTABLE_FORMAT set to GL_TRUE.
if (tex->IsImmutable()) {
ErrorInvalidOperation("%s: texture bound to target %s is already immutable", info, EnumName(target));
return false;
}
// GL_INVALID_ENUM is generated if internalformat is not a valid sized internal format.
if (!ValidateSizedInternalFormat(internalformat, info))
return false;
// GL_INVALID_VALUE is generated if width, height or levels are less than 1.
if (width < 1) { ErrorInvalidValue("%s: width is < 1", info); return false; }
if (height < 1) { ErrorInvalidValue("%s: height is < 1", info); return false; }
if (depth < 1) { ErrorInvalidValue("%s: depth is < 1", info); return false; }
if (levels < 1) { ErrorInvalidValue("%s: levels is < 1", info); return false; }
// The following check via FloorLog2 only requires a depth value if target is TEXTURE_3D.
bool is3D = (target != LOCAL_GL_TEXTURE_3D);
if (!is3D)
depth = 1;
// GL_INVALID_OPERATION is generated if levels is greater than floor(log2(max(width, height, depth)))+1.
if (FloorLog2(std::max(std::max(width, height), depth))+1 < levels) {
ErrorInvalidOperation("%s: levels > floor(log2(max(width, height%s)))+1", info, is3D ? ", depth" : "");
return false;
}
return true;
}
// -------------------------------------------------------------------------
// Texture objects
void
WebGL2Context::TexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
{
if (IsContextLost())
return;
// GL_INVALID_ENUM is generated if target is not one of the accepted target enumerants.
if (target != LOCAL_GL_TEXTURE_2D && target != LOCAL_GL_TEXTURE_CUBE_MAP)
return ErrorInvalidEnum("texStorage2D: target is not TEXTURE_2D or TEXTURE_CUBE_MAP.");
if (!ValidateTexStorage(target, levels, internalformat, width, height, 1, "texStorage2D"))
return;
WebGLTexture* tex = activeBoundTextureForTarget(target);
tex->SetImmutable();
const size_t facesCount = (target == LOCAL_GL_TEXTURE_2D) ? 1 : 6;
GLsizei w = width;
GLsizei h = height;
for (size_t l = 0; l < size_t(levels); l++) {
for (size_t f = 0; f < facesCount; f++) {
tex->SetImageInfo(TexImageTargetForTargetAndFace(target, f),
l, w, h,
internalformat,
WebGLImageDataStatus::UninitializedImageData);
}
w = std::max(1, w/2);
h = std::max(1, h/2);
}
gl->fTexStorage2D(target, levels, internalformat, width, height);
}
void
WebGL2Context::TexStorage3D(GLenum target, GLsizei levels, GLenum internalformat,
GLsizei width, GLsizei height, GLsizei depth)
{
MOZ_CRASH("Not Implemented.");
}
void
WebGL2Context::TexSubImage3D(GLenum target, GLint level,
GLint xoffset, GLint yoffset, GLint zoffset,
GLsizei width, GLsizei height, GLsizei depth,
GLenum format, GLenum type, const Nullable<dom::ArrayBufferView>& pixels,
ErrorResult& rv)
{
MOZ_CRASH("Not Implemented.");
}
void
WebGL2Context::TexSubImage3D(GLenum target, GLint level,
GLint xoffset, GLint yoffset, GLint zoffset,
GLenum format, GLenum type, dom::ImageData* data,
ErrorResult& rv)
{
MOZ_CRASH("Not Implemented.");
}
void
WebGL2Context::CopyTexSubImage3D(GLenum target, GLint level,
GLint xoffset, GLint yoffset, GLint zoffset,
GLint x, GLint y, GLsizei width, GLsizei height)
{
MOZ_CRASH("Not Implemented.");
}
void
WebGL2Context::CompressedTexImage3D(GLenum target, GLint level, GLenum internalformat,
GLsizei width, GLsizei height, GLsizei depth,
GLint border, GLsizei imageSize, const dom::ArrayBufferView& data)
{
MOZ_CRASH("Not Implemented.");
}
void
WebGL2Context::CompressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
GLsizei width, GLsizei height, GLsizei depth,
GLenum format, GLsizei imageSize, const dom::ArrayBufferView& data)
{
MOZ_CRASH("Not Implemented.");
}