Bug 1006908 - WebGL differentiate texture image targets vs texture binding locations better. r=jgilbert

This commit is contained in:
Walter Litwinczyk 2014-09-03 12:17:18 -07:00
Родитель 434d96be0b
Коммит b7556664b4
7 изменённых файлов: 125 добавлений и 54 удалений

Просмотреть файл

@ -271,7 +271,9 @@ WebGLContext::WebGLContext()
mGLMaxVertexAttribs = 0;
mGLMaxTextureUnits = 0;
mGLMaxTextureSize = 0;
mGLMaxTextureSizeLog2 = 0;
mGLMaxCubeMapTextureSize = 0;
mGLMaxCubeMapTextureSizeLog2 = 0;
mGLMaxRenderbufferSize = 0;
mGLMaxTextureImageUnits = 0;
mGLMaxVertexTextureImageUnits = 0;
@ -1738,7 +1740,7 @@ WebGLContext::GetSurfaceSnapshot(bool* aPremultAlpha)
return dt->Snapshot();
}
bool WebGLContext::TexImageFromVideoElement(GLenum target, GLint level,
bool WebGLContext::TexImageFromVideoElement(GLenum texImageTarget, GLint level,
GLenum internalformat, GLenum format, GLenum type,
mozilla::dom::Element& elt)
{
@ -1778,19 +1780,19 @@ bool WebGLContext::TexImageFromVideoElement(GLenum target, GLint level,
gl->MakeCurrent();
nsRefPtr<mozilla::layers::Image> srcImage = container->LockCurrentImage();
WebGLTexture* tex = activeBoundTextureForTarget(target);
WebGLTexture* tex = activeBoundTextureForTexImageTarget(texImageTarget);
const WebGLTexture::ImageInfo& info = tex->ImageInfoAt(target, 0);
const WebGLTexture::ImageInfo& info = tex->ImageInfoAt(texImageTarget, 0);
bool dimensionsMatch = info.Width() == srcImage->GetSize().width &&
info.Height() == srcImage->GetSize().height;
if (!dimensionsMatch) {
// we need to allocation
gl->fTexImage2D(target, level, internalformat, srcImage->GetSize().width, srcImage->GetSize().height, 0, format, type, nullptr);
gl->fTexImage2D(texImageTarget, level, internalformat, srcImage->GetSize().width, srcImage->GetSize().height, 0, format, type, nullptr);
}
bool ok = gl->BlitHelper()->BlitImageToTexture(srcImage.get(), srcImage->GetSize(), tex->GLName(), target, mPixelStoreFlipY);
bool ok = gl->BlitHelper()->BlitImageToTexture(srcImage.get(), srcImage->GetSize(), tex->GLName(), texImageTarget, mPixelStoreFlipY);
if (ok) {
tex->SetImageInfo(target, level, srcImage->GetSize().width, srcImage->GetSize().height, format, type, WebGLImageDataStatus::InitializedImageData);
tex->Bind(target);
tex->SetImageInfo(texImageTarget, level, srcImage->GetSize().width, srcImage->GetSize().height, format, type, WebGLImageDataStatus::InitializedImageData);
tex->Bind(TexImageTargetToTexTarget(texImageTarget));
}
srcImage = nullptr;
container->UnlockCurrentImage();

Просмотреть файл

@ -122,18 +122,8 @@ struct WebGLContextOptions {
bool preserveDrawingBuffer;
};
#ifdef DEBUG
static bool
IsTextureBinding(GLenum binding)
{
switch (binding) {
case LOCAL_GL_TEXTURE_BINDING_2D:
case LOCAL_GL_TEXTURE_BINDING_CUBE_MAP:
return true;
}
return false;
}
#endif
// From WebGLContextUtils
GLenum TexImageTargetToTexTarget(GLenum texImageTarget);
class WebGLContext :
public nsIDOMWebGLRenderingContext,
@ -232,10 +222,19 @@ public:
void DummyFramebufferOperation(const char *info);
WebGLTexture* activeBoundTextureForTarget(GLenum target) const {
MOZ_ASSERT(!IsTextureBinding(target));
return target == LOCAL_GL_TEXTURE_2D ? mBound2DTextures[mActiveTexture]
: mBoundCubeMapTextures[mActiveTexture];
WebGLTexture* activeBoundTextureForTarget(GLenum texTarget) const {
MOZ_ASSERT(texTarget == LOCAL_GL_TEXTURE_2D || texTarget == LOCAL_GL_TEXTURE_CUBE_MAP);
return texTarget == LOCAL_GL_TEXTURE_2D ? mBound2DTextures[mActiveTexture]
: mBoundCubeMapTextures[mActiveTexture];
}
/* Use this function when you have the texture image target, for example:
* GL_TEXTURE_2D, GL_TEXTURE_CUBE_MAP_[POSITIVE|NEGATIVE]_[X|Y|Z], and
* not the actual texture binding target: GL_TEXTURE_2D or GL_TEXTURE_CUBE_MAP.
*/
WebGLTexture* activeBoundTextureForTexImageTarget(GLenum texImgTarget) const {
const GLenum texTarget = TexImageTargetToTexTarget(texImgTarget);
return activeBoundTextureForTarget(texTarget);
}
already_AddRefed<CanvasLayer> GetCanvasLayer(nsDisplayListBuilder* aBuilder,
@ -464,25 +463,39 @@ public:
dom::ImageData* pixels, ErrorResult& rv);
// Allow whatever element types the bindings are willing to pass
// us in TexImage2D
bool TexImageFromVideoElement(GLenum target, GLint level,
bool TexImageFromVideoElement(GLenum texImageTarget, GLint level,
GLenum internalformat, GLenum format, GLenum type,
mozilla::dom::Element& image);
template<class ElementType>
void TexImage2D(GLenum target, GLint level,
void TexImage2D(GLenum texImageTarget, GLint level,
GLenum internalformat, GLenum format, GLenum type,
ElementType& elt, ErrorResult& rv)
{
if (IsContextLost())
return;
const GLenum target = TexImageTargetToTexTarget(texImageTarget);
if (target == LOCAL_GL_NONE)
return ErrorInvalidEnumInfo("texImage2D: target", target);
if (!ValidateTexImageFormatAndType(format, type, WebGLTexImageFunc::TexImage))
return;
if (level < 0)
return ErrorInvalidValue("texImage2D: level is negative");
const int32_t maxLevel = MaxTextureLevelForTexImageTarget(texImageTarget);
if (level > maxLevel)
return ErrorInvalidValue("texImage2D: level %d is too large, max is %d", level, maxLevel);
WebGLTexture* tex = activeBoundTextureForTarget(target);
if (!tex)
return ErrorInvalidOperation("no texture is bound to this target");
// Trying to handle the video by GPU directly first
if (TexImageFromVideoElement(target, level, internalformat, format, type, elt)) {
if (TexImageFromVideoElement(texImageTarget, level, internalformat, format, type, elt)) {
return;
}
@ -496,7 +509,7 @@ public:
gfx::IntSize size = data->GetSize();
uint32_t byteLength = data->Stride() * size.height;
return TexImage2D_base(target, level, internalformat,
return TexImage2D_base(texImageTarget, level, internalformat,
size.width, size.height, data->Stride(),
0, format, type, data->GetData(), byteLength,
-1, srcFormat, mPixelStorePremultiplyAlpha);
@ -971,7 +984,9 @@ protected:
int32_t mGLMaxVertexAttribs;
int32_t mGLMaxTextureUnits;
int32_t mGLMaxTextureSize;
int32_t mGLMaxTextureSizeLog2;
int32_t mGLMaxCubeMapTextureSize;
int32_t mGLMaxCubeMapTextureSizeLog2;
int32_t mGLMaxRenderbufferSize;
int32_t mGLMaxTextureImageUnits;
int32_t mGLMaxVertexTextureImageUnits;
@ -1177,6 +1192,12 @@ protected:
return (target == LOCAL_GL_TEXTURE_2D) ? mGLMaxTextureSize : mGLMaxCubeMapTextureSize;
}
int32_t MaxTextureLevelForTexImageTarget(GLenum texImageTarget) const {
const GLenum target = TexImageTargetToTexTarget(texImageTarget);
MOZ_ASSERT(target == LOCAL_GL_TEXTURE_2D || target == LOCAL_GL_TEXTURE_CUBE_MAP);
return (target == LOCAL_GL_TEXTURE_2D) ? mGLMaxTextureSizeLog2 : mGLMaxCubeMapTextureSizeLog2;
}
/** like glBufferData but if the call may change the buffer size, checks any GL error generated
* by this glBufferData call and returns it */
GLenum CheckedBufferData(GLenum target,

Просмотреть файл

@ -223,18 +223,26 @@ WebGLContext::BindTexture(GLenum target, WebGLTexture *newTex)
if (!ValidateObjectAllowDeletedOrNull("bindTexture", newTex))
return;
// silently ignore a deleted texture
if (newTex && newTex->IsDeleted())
return;
if (newTex) {
// silently ignore a deleted texture
if (newTex->IsDeleted())
return;
if (newTex->Target() != LOCAL_GL_NONE && newTex->Target() != target)
return ErrorInvalidOperation("bindTexture: this texture has already been bound to a different target");
}
WebGLRefPtr<WebGLTexture>* currentTexPtr = nullptr;
if (target == LOCAL_GL_TEXTURE_2D) {
currentTexPtr = &mBound2DTextures[mActiveTexture];
} else if (target == LOCAL_GL_TEXTURE_CUBE_MAP) {
currentTexPtr = &mBoundCubeMapTextures[mActiveTexture];
} else {
return ErrorInvalidEnumInfo("bindTexture: target", target);
switch (target) {
case LOCAL_GL_TEXTURE_2D:
currentTexPtr = &mBound2DTextures[mActiveTexture];
break;
case LOCAL_GL_TEXTURE_CUBE_MAP:
currentTexPtr = &mBoundCubeMapTextures[mActiveTexture];
break;
default:
return ErrorInvalidEnumInfo("bindTexture: target", target);
}
WebGLTextureFakeBlackStatus currentTexFakeBlackStatus = WebGLTextureFakeBlackStatus::NotNeeded;
@ -378,7 +386,7 @@ WebGLContext::CopyTexSubImage2D_base(GLenum target,
MakeContextCurrent();
WebGLTexture *tex = activeBoundTextureForTarget(target);
WebGLTexture *tex = activeBoundTextureForTexImageTarget(target);
if (!tex)
return ErrorInvalidOperation("%s: no texture is bound to this target");
@ -487,7 +495,7 @@ WebGLContext::CopyTexImage2D(GLenum target,
// check if the memory size of this texture may change with this call
bool sizeMayChange = true;
WebGLTexture* tex = activeBoundTextureForTarget(target);
WebGLTexture* tex = activeBoundTextureForTexImageTarget(target);
if (tex->HasImageInfoAt(target, level)) {
const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(target, level);
@ -553,7 +561,7 @@ WebGLContext::CopyTexSubImage2D(GLenum target,
if (xoffset < 0 || yoffset < 0)
return ErrorInvalidValue("copyTexSubImage2D: xoffset and yoffset may not be negative");
WebGLTexture *tex = activeBoundTextureForTarget(target);
WebGLTexture *tex = activeBoundTextureForTexImageTarget(target);
if (!tex)
return ErrorInvalidOperation("copyTexSubImage2D: no texture bound to this target");
@ -3299,7 +3307,7 @@ WebGLContext::CompressedTexImage2D(GLenum target, GLint level, GLenum internalfo
MakeContextCurrent();
gl->fCompressedTexImage2D(target, level, internalformat, width, height, border, byteLength, view.Data());
WebGLTexture* tex = activeBoundTextureForTarget(target);
WebGLTexture* tex = activeBoundTextureForTexImageTarget(target);
MOZ_ASSERT(tex);
tex->SetImageInfo(target, level, width, height, internalformat, LOCAL_GL_UNSIGNED_BYTE,
WebGLImageDataStatus::InitializedImageData);
@ -3325,7 +3333,7 @@ WebGLContext::CompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset,
return;
}
WebGLTexture *tex = activeBoundTextureForTarget(target);
WebGLTexture *tex = activeBoundTextureForTexImageTarget(target);
MOZ_ASSERT(tex);
WebGLTexture::ImageInfo& levelInfo = tex->ImageInfoAt(target, level);
@ -3546,7 +3554,7 @@ GLenum WebGLContext::CheckedTexImage2D(GLenum target,
const GLvoid *data)
{
MOZ_ASSERT(internalFormat == format);
WebGLTexture *tex = activeBoundTextureForTarget(target);
WebGLTexture *tex = activeBoundTextureForTexImageTarget(target);
MOZ_ASSERT(tex != nullptr, "no texture bound");
bool sizeMayChange = true;
@ -3633,7 +3641,7 @@ WebGLContext::TexImage2D_base(GLenum target, GLint level, GLenum internalformat,
return ErrorInvalidOperation("texImage2D: not enough data for operation (need %d, have %d)",
bytesNeeded, byteLength);
WebGLTexture *tex = activeBoundTextureForTarget(target);
WebGLTexture *tex = activeBoundTextureForTexImageTarget(target);
if (!tex)
return ErrorInvalidOperation("texImage2D: no texture is bound to this target");
@ -3789,7 +3797,7 @@ WebGLContext::TexSubImage2D_base(GLenum target, GLint level,
if (byteLength < bytesNeeded)
return ErrorInvalidOperation("texSubImage2D: not enough data for operation (need %d, have %d)", bytesNeeded, byteLength);
WebGLTexture *tex = activeBoundTextureForTarget(target);
WebGLTexture *tex = activeBoundTextureForTexImageTarget(target);
const WebGLTexture::ImageInfo &imageInfo = tex->ImageInfoAt(target, level);
if (imageInfo.HasUninitializedImageData())

Просмотреть файл

@ -56,6 +56,24 @@ FormatHasAlpha(GLenum webGLFormat)
webGLFormat == LOCAL_GL_SRGB_ALPHA;
}
GLenum
TexImageTargetToTexTarget(GLenum texImageTarget)
{
switch (texImageTarget) {
case LOCAL_GL_TEXTURE_2D:
return LOCAL_GL_TEXTURE_2D;
case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
return LOCAL_GL_TEXTURE_CUBE_MAP;
default:
return LOCAL_GL_NONE;
}
}
GLComponents::GLComponents(GLenum format)
{
mComponents = 0;

Просмотреть файл

@ -19,6 +19,20 @@ void DriverFormatsFromFormatAndType(gl::GLContext* gl, GLenum webGLFormat, GLenu
GLenum* out_driverInternalFormat, GLenum* out_driverFormat);
GLenum DriverTypeFromType(gl::GLContext* gl, GLenum webGLType);
// For use with the different texture calls, i.e.
// TexImage2D, CopyTex[Sub]Image2D, ...
// that take a "target" parameter. This parameter is not always the same as
// the texture binding location, like GL_TEXTURE_2D or GL_TEXTURE_CUBE_MAP.
// For example, cube maps would pass GL_TEXTURE_CUBE_MAP_[POS|NEG]_[X|Y|Z]
// instead of just GL_TEXTURE_CUBE_MAP.
//
// This function converts the texture image target to the texture target a.k.a.
// binding location. The returned binding location can be used to check that
// the currently bound texture is appropriate for this texImageTarget.
//
// Returns GL_NONE if passed an invalid texture image target
GLenum TexImageTargetToTexTarget(GLenum texImageTarget);
struct GLComponents
{
unsigned char mComponents;

Просмотреть файл

@ -1365,7 +1365,7 @@ WebGLContext::ValidateTexImage(GLuint dims, GLenum target,
* WebGLTexture bound (see above), an INVALID_OPERATION error
* is generated."
*/
WebGLTexture* tex = activeBoundTextureForTarget(target);
WebGLTexture* tex = activeBoundTextureForTexImageTarget(target);
if (!tex) {
ErrorInvalidOperation("%s: no texture is bound to target %s",
info, WebGLContext::EnumName(target));
@ -1735,6 +1735,19 @@ WebGLContext::InitAndValidateGL()
gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &mGLMaxVertexTextureImageUnits);
}
// Calculate log2 of mGLMaxTextureSize and mGLMaxCubeMapTextureSize
mGLMaxTextureSizeLog2 = 0;
int32_t tempSize = mGLMaxTextureSize;
while (tempSize >>= 1) {
++mGLMaxTextureSizeLog2;
}
mGLMaxCubeMapTextureSizeLog2 = 0;
tempSize = mGLMaxCubeMapTextureSize;
while (tempSize >>= 1) {
++mGLMaxCubeMapTextureSizeLog2;
}
mGLMaxTextureSize = floorPOT(mGLMaxTextureSize);
mGLMaxRenderbufferSize = floorPOT(mGLMaxRenderbufferSize);

Просмотреть файл

@ -137,22 +137,17 @@ WebGLTexture::Bind(GLenum aTarget) {
}
void
WebGLTexture::SetImageInfo(GLenum aTarget, GLint aLevel,
WebGLTexture::SetImageInfo(GLenum aTexImageTarget, GLint aLevel,
GLsizei aWidth, GLsizei aHeight,
GLenum aFormat, GLenum aType, WebGLImageDataStatus aStatus)
{
// TODO(djg): I suspected the following ASSERT and check are
// trying to express more than they're saying, probably
// to do with cubemap targets. We should do this
// properly. https://bugzilla.mozilla.org/show_bug.cgi?id=1006908
MOZ_ASSERT((aTarget == LOCAL_GL_TEXTURE_2D) == (mTarget == LOCAL_GL_TEXTURE_2D));
if ((aTarget == LOCAL_GL_TEXTURE_2D) != (mTarget == LOCAL_GL_TEXTURE_2D)) {
MOZ_ASSERT(TexImageTargetToTexTarget(aTexImageTarget) == mTarget);
if (TexImageTargetToTexTarget(aTexImageTarget) != mTarget)
return;
}
EnsureMaxLevelWithCustomImagesAtLeast(aLevel);
ImageInfoAt(aTarget, aLevel) = ImageInfo(aWidth, aHeight, aFormat, aType, aStatus);
ImageInfoAt(aTexImageTarget, aLevel) = ImageInfo(aWidth, aHeight, aFormat, aType, aStatus);
if (aLevel > 0)
SetCustomMipmap();