Commit c29968bb by Jamie Madill

Refactor FBO related entry points.

Change the validation to the consistent style for easy auto-generation and make the context itself implement the entry points. This will more easily allow us to sync state without passing the Context to the Texture methods, or doing work in the entry point. BUG=angleproject:1260 BUG=angleproject:747 Change-Id: I7ed6ec5418b7f51d9e59529267b14b76b87743fb Reviewed-on: https://chromium-review.googlesource.com/319823 Tryjob-Request: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Tested-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 45838e33
...@@ -857,8 +857,7 @@ Query *Context::getQuery(GLuint handle) const ...@@ -857,8 +857,7 @@ Query *Context::getQuery(GLuint handle) const
Texture *Context::getTargetTexture(GLenum target) const Texture *Context::getTargetTexture(GLenum target) const
{ {
ASSERT(ValidTextureTarget(this, target)); ASSERT(ValidTextureTarget(this, target));
return mState.getTargetTexture(target);
return getSamplerTexture(mState.getActiveSampler(), target);
} }
Texture *Context::getSamplerTexture(unsigned int sampler, GLenum type) const Texture *Context::getSamplerTexture(unsigned int sampler, GLenum type) const
...@@ -1936,4 +1935,346 @@ void Context::syncRendererState(const State::DirtyBits &bitMask) ...@@ -1936,4 +1935,346 @@ void Context::syncRendererState(const State::DirtyBits &bitMask)
mState.clearDirtyBits(dirtyBits); mState.clearDirtyBits(dirtyBits);
} }
} }
void Context::blitFramebuffer(GLint srcX0,
GLint srcY0,
GLint srcX1,
GLint srcY1,
GLint dstX0,
GLint dstY0,
GLint dstX1,
GLint dstY1,
GLbitfield mask,
GLenum filter)
{
Framebuffer *readFramebuffer = mState.getReadFramebuffer();
ASSERT(readFramebuffer);
Framebuffer *drawFramebuffer = mState.getDrawFramebuffer();
ASSERT(drawFramebuffer);
Rectangle srcArea(srcX0, srcY0, srcX1 - srcX0, srcY1 - srcY0);
Rectangle dstArea(dstX0, dstY0, dstX1 - dstX0, dstY1 - dstY0);
syncRendererState(mState.blitStateBitMask());
Error error = drawFramebuffer->blit(mState, srcArea, dstArea, mask, filter, readFramebuffer);
if (error.isError())
{
recordError(error);
return;
}
}
void Context::clear(GLbitfield mask)
{
// Sync the clear state
syncRendererState(mState.clearStateBitMask());
Error error = mState.getDrawFramebuffer()->clear(mData, mask);
if (error.isError())
{
recordError(error);
}
}
void Context::clearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *values)
{
// Sync the clear state
syncRendererState(mState.clearStateBitMask());
Error error = mState.getDrawFramebuffer()->clearBufferfv(mData, buffer, drawbuffer, values);
if (error.isError())
{
recordError(error);
}
}
void Context::clearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint *values)
{
// Sync the clear state
syncRendererState(mState.clearStateBitMask());
Error error = mState.getDrawFramebuffer()->clearBufferuiv(mData, buffer, drawbuffer, values);
if (error.isError())
{
recordError(error);
}
}
void Context::clearBufferiv(GLenum buffer, GLint drawbuffer, const GLint *values)
{
// Sync the clear state
syncRendererState(mState.clearStateBitMask());
Error error = mState.getDrawFramebuffer()->clearBufferiv(mData, buffer, drawbuffer, values);
if (error.isError())
{
recordError(error);
}
} }
void Context::clearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil)
{
Framebuffer *framebufferObject = mState.getDrawFramebuffer();
ASSERT(framebufferObject);
// If a buffer is not present, the clear has no effect
if (framebufferObject->getDepthbuffer() == nullptr &&
framebufferObject->getStencilbuffer() == nullptr)
{
return;
}
// Sync the clear state
syncRendererState(mState.clearStateBitMask());
Error error = framebufferObject->clearBufferfi(mData, buffer, drawbuffer, depth, stencil);
if (error.isError())
{
recordError(error);
}
}
void Context::readPixels(GLint x,
GLint y,
GLsizei width,
GLsizei height,
GLenum format,
GLenum type,
GLvoid *pixels)
{
// Sync pack state
syncRendererState(mState.packStateBitMask());
Framebuffer *framebufferObject = mState.getReadFramebuffer();
ASSERT(framebufferObject);
Rectangle area(x, y, width, height);
Error error = framebufferObject->readPixels(mState, area, format, type, pixels);
if (error.isError())
{
recordError(error);
}
}
void Context::copyTexImage2D(GLenum target,
GLint level,
GLenum internalformat,
GLint x,
GLint y,
GLsizei width,
GLsizei height,
GLint border)
{
Rectangle sourceArea(x, y, width, height);
const Framebuffer *framebuffer = mState.getReadFramebuffer();
Texture *texture =
getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Error error = texture->copyImage(target, level, sourceArea, internalformat, framebuffer);
if (error.isError())
{
recordError(error);
}
}
void Context::copyTexSubImage2D(GLenum target,
GLint level,
GLint xoffset,
GLint yoffset,
GLint x,
GLint y,
GLsizei width,
GLsizei height)
{
Offset destOffset(xoffset, yoffset, 0);
Rectangle sourceArea(x, y, width, height);
const Framebuffer *framebuffer = mState.getReadFramebuffer();
Texture *texture =
getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Error error = texture->copySubImage(target, level, destOffset, sourceArea, framebuffer);
if (error.isError())
{
recordError(error);
}
}
void Context::copyTexSubImage3D(GLenum target,
GLint level,
GLint xoffset,
GLint yoffset,
GLint zoffset,
GLint x,
GLint y,
GLsizei width,
GLsizei height)
{
Offset destOffset(xoffset, yoffset, zoffset);
Rectangle sourceArea(x, y, width, height);
const Framebuffer *framebuffer = mState.getReadFramebuffer();
Texture *texture = getTargetTexture(target);
Error error = texture->copySubImage(target, level, destOffset, sourceArea, framebuffer);
if (error.isError())
{
recordError(error);
}
}
void Context::framebufferTexture2D(GLenum target,
GLenum attachment,
GLenum textarget,
GLuint texture,
GLint level)
{
Framebuffer *framebuffer = mState.getTargetFramebuffer(target);
ASSERT(framebuffer);
if (texture != 0)
{
Texture *textureObj = getTexture(texture);
ImageIndex index = ImageIndex::MakeInvalid();
if (textarget == GL_TEXTURE_2D)
{
index = ImageIndex::Make2D(level);
}
else
{
ASSERT(IsCubeMapTextureTarget(textarget));
index = ImageIndex::MakeCube(textarget, level);
}
framebuffer->setAttachment(GL_TEXTURE, attachment, index, textureObj);
}
else
{
framebuffer->resetAttachment(attachment);
}
}
void Context::framebufferRenderbuffer(GLenum target,
GLenum attachment,
GLenum renderbuffertarget,
GLuint renderbuffer)
{
Framebuffer *framebuffer = mState.getTargetFramebuffer(target);
ASSERT(framebuffer);
if (renderbuffer != 0)
{
Renderbuffer *renderbufferObject = getRenderbuffer(renderbuffer);
framebuffer->setAttachment(GL_RENDERBUFFER, attachment, gl::ImageIndex::MakeInvalid(),
renderbufferObject);
}
else
{
framebuffer->resetAttachment(attachment);
}
}
void Context::framebufferTextureLayer(GLenum target,
GLenum attachment,
GLuint texture,
GLint level,
GLint layer)
{
Framebuffer *framebuffer = mState.getTargetFramebuffer(target);
ASSERT(framebuffer);
if (texture != 0)
{
Texture *textureObject = getTexture(texture);
ImageIndex index = ImageIndex::MakeInvalid();
if (textureObject->getTarget() == GL_TEXTURE_3D)
{
index = ImageIndex::Make3D(level, layer);
}
else
{
ASSERT(textureObject->getTarget() == GL_TEXTURE_2D_ARRAY);
index = ImageIndex::Make2DArray(level, layer);
}
framebuffer->setAttachment(GL_TEXTURE, attachment, index, textureObject);
}
else
{
framebuffer->resetAttachment(attachment);
}
}
void Context::drawBuffers(GLsizei n, const GLenum *bufs)
{
Framebuffer *framebuffer = mState.getDrawFramebuffer();
ASSERT(framebuffer);
framebuffer->setDrawBuffers(n, bufs);
}
void Context::readBuffer(GLenum mode)
{
Framebuffer *readFBO = mState.getReadFramebuffer();
readFBO->setReadBuffer(mode);
}
void Context::discardFramebuffer(GLenum target, GLsizei numAttachments, const GLenum *attachments)
{
Framebuffer *framebuffer = mState.getTargetFramebuffer(target);
ASSERT(framebuffer);
// The specification isn't clear what should be done when the framebuffer isn't complete.
// We leave it up to the framebuffer implementation to decide what to do.
Error error = framebuffer->discard(numAttachments, attachments);
if (error.isError())
{
recordError(error);
}
}
void Context::invalidateFramebuffer(GLenum target,
GLsizei numAttachments,
const GLenum *attachments)
{
Framebuffer *framebuffer = mState.getTargetFramebuffer(target);
ASSERT(framebuffer);
if (framebuffer->checkStatus(mData) == GL_FRAMEBUFFER_COMPLETE)
{
Error error = framebuffer->invalidate(numAttachments, attachments);
if (error.isError())
{
recordError(error);
return;
}
}
}
void Context::invalidateSubFramebuffer(GLenum target,
GLsizei numAttachments,
const GLenum *attachments,
GLint x,
GLint y,
GLsizei width,
GLsizei height)
{
Framebuffer *framebuffer = mState.getTargetFramebuffer(target);
ASSERT(framebuffer);
if (framebuffer->checkStatus(mData) == GL_FRAMEBUFFER_COMPLETE)
{
Rectangle area(x, y, width, height);
Error error = framebuffer->invalidateSub(numAttachments, attachments, area);
if (error.isError())
{
recordError(error);
return;
}
}
}
} // namespace gl
...@@ -175,6 +175,12 @@ class Context final : public ValidationContext ...@@ -175,6 +175,12 @@ class Context final : public ValidationContext
bool getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *numParams); bool getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *numParams);
bool getIndexedQueryParameterInfo(GLenum target, GLenum *type, unsigned int *numParams); bool getIndexedQueryParameterInfo(GLenum target, GLenum *type, unsigned int *numParams);
void clear(GLbitfield mask);
void clearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *values);
void clearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint *values);
void clearBufferiv(GLenum buffer, GLint drawbuffer, const GLint *values);
void clearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
Error drawArrays(GLenum mode, GLint first, GLsizei count); Error drawArrays(GLenum mode, GLint first, GLsizei count);
Error drawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount); Error drawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount);
...@@ -197,6 +203,83 @@ class Context final : public ValidationContext ...@@ -197,6 +203,83 @@ class Context final : public ValidationContext
const GLvoid *indices, const GLvoid *indices,
const IndexRange &indexRange); const IndexRange &indexRange);
void blitFramebuffer(GLint srcX0,
GLint srcY0,
GLint srcX1,
GLint srcY1,
GLint dstX0,
GLint dstY0,
GLint dstX1,
GLint dstY1,
GLbitfield mask,
GLenum filter);
void readPixels(GLint x,
GLint y,
GLsizei width,
GLsizei height,
GLenum format,
GLenum type,
GLvoid *pixels);
void copyTexImage2D(GLenum target,
GLint level,
GLenum internalformat,
GLint x,
GLint y,
GLsizei width,
GLsizei height,
GLint border);
void copyTexSubImage2D(GLenum target,
GLint level,
GLint xoffset,
GLint yoffset,
GLint x,
GLint y,
GLsizei width,
GLsizei height);
void copyTexSubImage3D(GLenum target,
GLint level,
GLint xoffset,
GLint yoffset,
GLint zoffset,
GLint x,
GLint y,
GLsizei width,
GLsizei height);
void framebufferTexture2D(GLenum target,
GLenum attachment,
GLenum textarget,
GLuint texture,
GLint level);
void framebufferRenderbuffer(GLenum target,
GLenum attachment,
GLenum renderbuffertarget,
GLuint renderbuffer);
void framebufferTextureLayer(GLenum target,
GLenum attachment,
GLuint texture,
GLint level,
GLint layer);
void drawBuffers(GLsizei n, const GLenum *bufs);
void readBuffer(GLenum mode);
void discardFramebuffer(GLenum target, GLsizei numAttachments, const GLenum *attachments);
void invalidateFramebuffer(GLenum target, GLsizei numAttachments, const GLenum *attachments);
void invalidateSubFramebuffer(GLenum target,
GLsizei numAttachments,
const GLenum *attachments,
GLint x,
GLint y,
GLsizei width,
GLsizei height);
Error flush(); Error flush();
Error finish(); Error finish();
......
...@@ -590,81 +590,67 @@ Error Framebuffer::invalidateSub(size_t count, const GLenum *attachments, const ...@@ -590,81 +590,67 @@ Error Framebuffer::invalidateSub(size_t count, const GLenum *attachments, const
return mImpl->invalidateSub(count, attachments, area); return mImpl->invalidateSub(count, attachments, area);
} }
Error Framebuffer::clear(Context *context, GLbitfield mask) Error Framebuffer::clear(const gl::Data &data, GLbitfield mask)
{ {
if (context->getState().isRasterizerDiscardEnabled()) if (data.state->isRasterizerDiscardEnabled())
{ {
return gl::Error(GL_NO_ERROR); return gl::Error(GL_NO_ERROR);
} }
// Sync the clear state return mImpl->clear(data, mask);
context->syncRendererState(context->getState().clearStateBitMask());
return mImpl->clear(context->getData(), mask);
} }
Error Framebuffer::clearBufferfv(Context *context, Error Framebuffer::clearBufferfv(const gl::Data &data,
GLenum buffer, GLenum buffer,
GLint drawbuffer, GLint drawbuffer,
const GLfloat *values) const GLfloat *values)
{ {
if (context->getState().isRasterizerDiscardEnabled()) if (data.state->isRasterizerDiscardEnabled())
{ {
return gl::Error(GL_NO_ERROR); return gl::Error(GL_NO_ERROR);
} }
// Sync the clear state return mImpl->clearBufferfv(data, buffer, drawbuffer, values);
context->syncRendererState(context->getState().clearStateBitMask());
return mImpl->clearBufferfv(context->getData(), buffer, drawbuffer, values);
} }
Error Framebuffer::clearBufferuiv(Context *context, Error Framebuffer::clearBufferuiv(const gl::Data &data,
GLenum buffer, GLenum buffer,
GLint drawbuffer, GLint drawbuffer,
const GLuint *values) const GLuint *values)
{ {
if (context->getState().isRasterizerDiscardEnabled()) if (data.state->isRasterizerDiscardEnabled())
{ {
return gl::Error(GL_NO_ERROR); return gl::Error(GL_NO_ERROR);
} }
// Sync the clear state return mImpl->clearBufferuiv(data, buffer, drawbuffer, values);
context->syncRendererState(context->getState().clearStateBitMask());
return mImpl->clearBufferuiv(context->getData(), buffer, drawbuffer, values);
} }
Error Framebuffer::clearBufferiv(Context *context, Error Framebuffer::clearBufferiv(const gl::Data &data,
GLenum buffer, GLenum buffer,
GLint drawbuffer, GLint drawbuffer,
const GLint *values) const GLint *values)
{ {
if (context->getState().isRasterizerDiscardEnabled()) if (data.state->isRasterizerDiscardEnabled())
{ {
return gl::Error(GL_NO_ERROR); return gl::Error(GL_NO_ERROR);
} }
// Sync the clear state return mImpl->clearBufferiv(data, buffer, drawbuffer, values);
context->syncRendererState(context->getState().clearStateBitMask());
return mImpl->clearBufferiv(context->getData(), buffer, drawbuffer, values);
} }
Error Framebuffer::clearBufferfi(Context *context, Error Framebuffer::clearBufferfi(const gl::Data &data,
GLenum buffer, GLenum buffer,
GLint drawbuffer, GLint drawbuffer,
GLfloat depth, GLfloat depth,
GLint stencil) GLint stencil)
{ {
if (context->getState().isRasterizerDiscardEnabled()) if (data.state->isRasterizerDiscardEnabled())
{ {
return gl::Error(GL_NO_ERROR); return gl::Error(GL_NO_ERROR);
} }
// Sync the clear state return mImpl->clearBufferfi(data, buffer, drawbuffer, depth, stencil);
context->syncRendererState(context->getState().clearStateBitMask());
return mImpl->clearBufferfi(context->getData(), buffer, drawbuffer, depth, stencil);
} }
GLenum Framebuffer::getImplementationColorReadFormat() const GLenum Framebuffer::getImplementationColorReadFormat() const
...@@ -677,17 +663,12 @@ GLenum Framebuffer::getImplementationColorReadType() const ...@@ -677,17 +663,12 @@ GLenum Framebuffer::getImplementationColorReadType() const
return mImpl->getImplementationColorReadType(); return mImpl->getImplementationColorReadType();
} }
Error Framebuffer::readPixels(Context *context, Error Framebuffer::readPixels(const State &state,
const gl::Rectangle &area, const Rectangle &area,
GLenum format, GLenum format,
GLenum type, GLenum type,
GLvoid *pixels) const GLvoid *pixels) const
{ {
const State &state = context->getState();
// Sync pack state
context->syncRendererState(state.packStateBitMask());
Error error = mImpl->readPixels(state, area, format, type, pixels); Error error = mImpl->readPixels(state, area, format, type, pixels);
if (error.isError()) if (error.isError())
{ {
...@@ -703,17 +684,13 @@ Error Framebuffer::readPixels(Context *context, ...@@ -703,17 +684,13 @@ Error Framebuffer::readPixels(Context *context,
return Error(GL_NO_ERROR); return Error(GL_NO_ERROR);
} }
Error Framebuffer::blit(Context *context, Error Framebuffer::blit(const State &state,
const gl::Rectangle &sourceArea, const Rectangle &sourceArea,
const gl::Rectangle &destArea, const Rectangle &destArea,
GLbitfield mask, GLbitfield mask,
GLenum filter, GLenum filter,
const gl::Framebuffer *sourceFramebuffer) const Framebuffer *sourceFramebuffer)
{ {
// Sync blit state
const State &state = context->getState();
context->syncRendererState(state.blitStateBitMask());
return mImpl->blit(state, sourceArea, destArea, mask, filter, sourceFramebuffer); return mImpl->blit(state, sourceArea, destArea, mask, filter, sourceFramebuffer);
} }
......
...@@ -137,11 +137,17 @@ class Framebuffer final : public LabeledObject ...@@ -137,11 +137,17 @@ class Framebuffer final : public LabeledObject
Error invalidate(size_t count, const GLenum *attachments); Error invalidate(size_t count, const GLenum *attachments);
Error invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area); Error invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area);
Error clear(Context *context, GLbitfield mask); Error clear(const gl::Data &data, GLbitfield mask);
Error clearBufferfv(Context *context, GLenum buffer, GLint drawbuffer, const GLfloat *values); Error clearBufferfv(const gl::Data &data,
Error clearBufferuiv(Context *context, GLenum buffer, GLint drawbuffer, const GLuint *values); GLenum buffer,
Error clearBufferiv(Context *context, GLenum buffer, GLint drawbuffer, const GLint *values); GLint drawbuffer,
Error clearBufferfi(Context *context, const GLfloat *values);
Error clearBufferuiv(const gl::Data &data,
GLenum buffer,
GLint drawbuffer,
const GLuint *values);
Error clearBufferiv(const gl::Data &data, GLenum buffer, GLint drawbuffer, const GLint *values);
Error clearBufferfi(const gl::Data &data,
GLenum buffer, GLenum buffer,
GLint drawbuffer, GLint drawbuffer,
GLfloat depth, GLfloat depth,
...@@ -149,18 +155,18 @@ class Framebuffer final : public LabeledObject ...@@ -149,18 +155,18 @@ class Framebuffer final : public LabeledObject
GLenum getImplementationColorReadFormat() const; GLenum getImplementationColorReadFormat() const;
GLenum getImplementationColorReadType() const; GLenum getImplementationColorReadType() const;
Error readPixels(Context *context, Error readPixels(const gl::State &state,
const gl::Rectangle &area, const gl::Rectangle &area,
GLenum format, GLenum format,
GLenum type, GLenum type,
GLvoid *pixels) const; GLvoid *pixels) const;
Error blit(Context *context, Error blit(const State &state,
const gl::Rectangle &sourceArea, const Rectangle &sourceArea,
const gl::Rectangle &destArea, const Rectangle &destArea,
GLbitfield mask, GLbitfield mask,
GLenum filter, GLenum filter,
const gl::Framebuffer *sourceFramebuffer); const Framebuffer *sourceFramebuffer);
protected: protected:
void detachResourceById(GLenum resourceType, GLuint resourceId); void detachResourceById(GLenum resourceType, GLuint resourceId);
......
...@@ -676,6 +676,11 @@ void State::setSamplerTexture(GLenum type, Texture *texture) ...@@ -676,6 +676,11 @@ void State::setSamplerTexture(GLenum type, Texture *texture)
mSamplerTextures[type][mActiveSampler].set(texture); mSamplerTextures[type][mActiveSampler].set(texture);
} }
Texture *State::getTargetTexture(GLenum target) const
{
return getSamplerTexture(static_cast<unsigned int>(mActiveSampler), target);
}
Texture *State::getSamplerTexture(unsigned int sampler, GLenum type) const Texture *State::getSamplerTexture(unsigned int sampler, GLenum type) const
{ {
const auto it = mSamplerTextures.find(type); const auto it = mSamplerTextures.find(type);
......
...@@ -149,6 +149,7 @@ class State : angle::NonCopyable ...@@ -149,6 +149,7 @@ class State : angle::NonCopyable
void setActiveSampler(unsigned int active); void setActiveSampler(unsigned int active);
unsigned int getActiveSampler() const; unsigned int getActiveSampler() const;
void setSamplerTexture(GLenum type, Texture *texture); void setSamplerTexture(GLenum type, Texture *texture);
Texture *getTargetTexture(GLenum target) const;
Texture *getSamplerTexture(unsigned int sampler, GLenum type) const; Texture *getSamplerTexture(unsigned int sampler, GLenum type) const;
GLuint getSamplerTextureId(unsigned int sampler, GLenum type) const; GLuint getSamplerTextureId(unsigned int sampler, GLenum type) const;
void detachTexture(const TextureMap &zeroTextures, GLuint texture); void detachTexture(const TextureMap &zeroTextures, GLuint texture);
......
...@@ -144,7 +144,7 @@ bool ValidTextureTarget(const Context *context, GLenum target) ...@@ -144,7 +144,7 @@ bool ValidTextureTarget(const Context *context, GLenum target)
// usable as the destination of a 2D operation-- so a cube face is valid, but // usable as the destination of a 2D operation-- so a cube face is valid, but
// GL_TEXTURE_CUBE_MAP is not. // GL_TEXTURE_CUBE_MAP is not.
// Note: duplicate of IsInternalTextureTarget // Note: duplicate of IsInternalTextureTarget
bool ValidTexture2DDestinationTarget(const Context *context, GLenum target) bool ValidTexture2DDestinationTarget(const ValidationContext *context, GLenum target)
{ {
switch (target) switch (target)
{ {
...@@ -230,21 +230,30 @@ bool ValidBufferParameter(const Context *context, GLenum pname) ...@@ -230,21 +230,30 @@ bool ValidBufferParameter(const Context *context, GLenum pname)
} }
} }
bool ValidMipLevel(const Context *context, GLenum target, GLint level) bool ValidMipLevel(const ValidationContext *context, GLenum target, GLint level)
{ {
const auto &caps = context->getCaps();
size_t maxDimension = 0; size_t maxDimension = 0;
switch (target) switch (target)
{ {
case GL_TEXTURE_2D: maxDimension = context->getCaps().max2DTextureSize; break; case GL_TEXTURE_2D:
maxDimension = caps.max2DTextureSize;
break;
case GL_TEXTURE_CUBE_MAP: case GL_TEXTURE_CUBE_MAP:
case GL_TEXTURE_CUBE_MAP_POSITIVE_X: case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: maxDimension = context->getCaps().maxCubeMapTextureSize; break; case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
case GL_TEXTURE_3D: maxDimension = context->getCaps().max3DTextureSize; break; maxDimension = caps.maxCubeMapTextureSize;
case GL_TEXTURE_2D_ARRAY: maxDimension = context->getCaps().max2DTextureSize; break; break;
case GL_TEXTURE_3D:
maxDimension = caps.max3DTextureSize;
break;
case GL_TEXTURE_2D_ARRAY:
maxDimension = caps.max2DTextureSize;
break;
default: UNREACHABLE(); default: UNREACHABLE();
} }
...@@ -297,7 +306,10 @@ bool CompressedTextureFormatRequiresExactSize(GLenum internalFormat) ...@@ -297,7 +306,10 @@ bool CompressedTextureFormatRequiresExactSize(GLenum internalFormat)
} }
} }
bool ValidCompressedImageSize(const Context *context, GLenum internalFormat, GLsizei width, GLsizei height) bool ValidCompressedImageSize(const ValidationContext *context,
GLenum internalFormat,
GLsizei width,
GLsizei height)
{ {
const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat); const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
if (!formatInfo.compressed) if (!formatInfo.compressed)
...@@ -545,45 +557,23 @@ bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum targ ...@@ -545,45 +557,23 @@ bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum targ
return true; return true;
} }
static bool IsPartialBlit(gl::Context *context, const gl::FramebufferAttachment *readBuffer, const gl::FramebufferAttachment *writeBuffer, bool ValidateBlitFramebufferParameters(gl::Context *context,
GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint srcX0,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1) GLint srcY0,
{ GLint srcX1,
const Extents &writeSize = writeBuffer->getSize(); GLint srcY1,
const Extents &readSize = readBuffer->getSize(); GLint dstX0,
GLint dstY0,
if (srcX0 != 0 || srcY0 != 0 || dstX0 != 0 || dstY0 != 0 || dstX1 != writeSize.width || GLint dstX1,
dstY1 != writeSize.height || srcX1 != readSize.width || srcY1 != readSize.height) GLint dstY1,
{ GLbitfield mask,
return true; GLenum filter)
}
else if (context->getState().isScissorTestEnabled())
{
const Rectangle &scissor = context->getState().getScissor();
return scissor.x > 0 || scissor.y > 0 || scissor.width < writeSize.width ||
scissor.height < writeSize.height;
}
else
{
return false;
}
}
bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
GLenum filter, bool fromAngleExtension)
{ {
switch (filter) switch (filter)
{ {
case GL_NEAREST: case GL_NEAREST:
break; break;
case GL_LINEAR: case GL_LINEAR:
if (fromAngleExtension)
{
context->recordError(Error(GL_INVALID_ENUM));
return false;
}
break; break;
default: default:
context->recordError(Error(GL_INVALID_ENUM)); context->recordError(Error(GL_INVALID_ENUM));
...@@ -603,13 +593,6 @@ bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint ...@@ -603,13 +593,6 @@ bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint
return false; return false;
} }
if (fromAngleExtension && (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0))
{
ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation.");
context->recordError(Error(GL_INVALID_OPERATION));
return false;
}
// ES3.0 spec, section 4.3.2 states that linear filtering is only available for the // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
// color buffer, leaving only nearest being unfiltered from above // color buffer, leaving only nearest being unfiltered from above
if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST) if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
...@@ -620,11 +603,6 @@ bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint ...@@ -620,11 +603,6 @@ bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint
if (context->getState().getReadFramebuffer()->id() == context->getState().getDrawFramebuffer()->id()) if (context->getState().getReadFramebuffer()->id() == context->getState().getDrawFramebuffer()->id())
{ {
if (fromAngleExtension)
{
ERR("Blits with the same source and destination framebuffer are not supported by this "
"implementation.");
}
context->recordError(Error(GL_INVALID_OPERATION)); context->recordError(Error(GL_INVALID_OPERATION));
return false; return false;
} }
...@@ -737,54 +715,6 @@ bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint ...@@ -737,54 +715,6 @@ bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint
context->recordError(Error(GL_INVALID_OPERATION)); context->recordError(Error(GL_INVALID_OPERATION));
return false; return false;
} }
if (fromAngleExtension)
{
const FramebufferAttachment *readColorAttachment = readFramebuffer->getReadColorbuffer();
if (!readColorAttachment ||
(!(readColorAttachment->type() == GL_TEXTURE && readColorAttachment->getTextureImageIndex().type == GL_TEXTURE_2D) &&
readColorAttachment->type() != GL_RENDERBUFFER &&
readColorAttachment->type() != GL_FRAMEBUFFER_DEFAULT))
{
context->recordError(Error(GL_INVALID_OPERATION));
return false;
}
for (size_t colorAttachment = 0;
colorAttachment < drawFramebuffer->getNumColorBuffers(); ++colorAttachment)
{
if (drawFramebuffer->isEnabledColorAttachment(colorAttachment))
{
const FramebufferAttachment *attachment = drawFramebuffer->getColorbuffer(colorAttachment);
ASSERT(attachment);
if (!(attachment->type() == GL_TEXTURE && attachment->getTextureImageIndex().type == GL_TEXTURE_2D) &&
attachment->type() != GL_RENDERBUFFER &&
attachment->type() != GL_FRAMEBUFFER_DEFAULT)
{
context->recordError(Error(GL_INVALID_OPERATION));
return false;
}
// Return an error if the destination formats do not match
if (attachment->getInternalFormat() != readColorBuffer->getInternalFormat())
{
context->recordError(Error(GL_INVALID_OPERATION));
return false;
}
}
}
int readSamples = readFramebuffer->getSamples(context->getData());
if (readSamples != 0 && IsPartialBlit(context, readColorBuffer, drawColorBuffer,
srcX0, srcY0, srcX1, srcY1,
dstX0, dstY0, dstX1, dstY1))
{
context->recordError(Error(GL_INVALID_OPERATION));
return false;
}
}
} }
} }
...@@ -810,23 +740,6 @@ bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint ...@@ -810,23 +740,6 @@ bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint
context->recordError(Error(GL_INVALID_OPERATION)); context->recordError(Error(GL_INVALID_OPERATION));
return false; return false;
} }
if (fromAngleExtension)
{
if (IsPartialBlit(context, readBuffer, drawBuffer,
srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
{
ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
context->recordError(Error(GL_INVALID_OPERATION)); // only whole-buffer copies are permitted
return false;
}
if (readBuffer->getSamples() != 0 || drawBuffer->getSamples() != 0)
{
context->recordError(Error(GL_INVALID_OPERATION));
return false;
}
}
} }
} }
} }
...@@ -1056,10 +969,22 @@ bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname) ...@@ -1056,10 +969,22 @@ bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
} }
} }
bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsizei width, GLsizei height, bool ValidateReadPixels(Context *context,
GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels) GLint x,
GLint y,
GLsizei width,
GLsizei height,
GLenum format,
GLenum type,
GLvoid *pixels)
{ {
gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer(); if (width < 0 || height < 0)
{
context->recordError(Error(GL_INVALID_VALUE, "width and height must be positive"));
return false;
}
Framebuffer *framebuffer = context->getState().getReadFramebuffer();
ASSERT(framebuffer); ASSERT(framebuffer);
if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE) if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
...@@ -1096,6 +1021,25 @@ bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsize ...@@ -1096,6 +1021,25 @@ bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsize
return false; return false;
} }
return true;
}
bool ValidateReadnPixelsEXT(Context *context,
GLint x,
GLint y,
GLsizei width,
GLsizei height,
GLenum format,
GLenum type,
GLsizei bufSize,
GLvoid *pixels)
{
if (bufSize < 0)
{
context->recordError(Error(GL_INVALID_VALUE, "bufSize must be a positive number"));
return false;
}
GLenum sizedInternalFormat = GetSizedInternalFormat(format, type); GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat); const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
...@@ -1103,17 +1047,14 @@ bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsize ...@@ -1103,17 +1047,14 @@ bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsize
sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment(), sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment(),
context->getState().getPackRowLength()); context->getState().getPackRowLength());
// sized query sanity check // sized query sanity check
if (bufSize) int requiredSize = outputPitch * height;
if (requiredSize > bufSize)
{ {
int requiredSize = outputPitch * height; context->recordError(Error(GL_INVALID_OPERATION));
if (requiredSize > *bufSize) return false;
{
context->recordError(Error(GL_INVALID_OPERATION));
return false;
}
} }
return true; return ValidateReadPixels(context, x, y, width, height, format, type, pixels);
} }
bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id) bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id)
...@@ -1359,9 +1300,20 @@ bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, ...@@ -1359,9 +1300,20 @@ bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType,
return true; return true;
} }
bool ValidateCopyTexImageParametersBase(gl::Context *context, GLenum target, GLint level, GLenum internalformat, bool isSubImage, bool ValidateCopyTexImageParametersBase(ValidationContext *context,
GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, GLenum target,
GLint border, GLenum *textureFormatOut) GLint level,
GLenum internalformat,
bool isSubImage,
GLint xoffset,
GLint yoffset,
GLint zoffset,
GLint x,
GLint y,
GLsizei width,
GLsizei height,
GLint border,
GLenum *textureFormatOut)
{ {
if (!ValidTexture2DDestinationTarget(context, target)) if (!ValidTexture2DDestinationTarget(context, target))
...@@ -1394,14 +1346,15 @@ bool ValidateCopyTexImageParametersBase(gl::Context *context, GLenum target, GLi ...@@ -1394,14 +1346,15 @@ bool ValidateCopyTexImageParametersBase(gl::Context *context, GLenum target, GLi
return false; return false;
} }
gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer(); const gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE) if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
{ {
context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
return false; return false;
} }
if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples(context->getData()) != 0) const auto &state = context->getState();
if (state.getReadFramebuffer()->id() != 0 && framebuffer->getSamples(context->getData()) != 0)
{ {
context->recordError(Error(GL_INVALID_OPERATION)); context->recordError(Error(GL_INVALID_OPERATION));
return false; return false;
...@@ -1438,7 +1391,8 @@ bool ValidateCopyTexImageParametersBase(gl::Context *context, GLenum target, GLi ...@@ -1438,7 +1391,8 @@ bool ValidateCopyTexImageParametersBase(gl::Context *context, GLenum target, GLi
return false; return false;
} }
gl::Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target); gl::Texture *texture =
state.getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
if (!texture) if (!texture)
{ {
context->recordError(Error(GL_INVALID_OPERATION)); context->recordError(Error(GL_INVALID_OPERATION));
...@@ -2300,4 +2254,128 @@ bool ValidateGetProgramBinaryBase(Context *context, ...@@ -2300,4 +2254,128 @@ bool ValidateGetProgramBinaryBase(Context *context,
return true; return true;
} }
bool ValidateCopyTexImage2D(ValidationContext *context,
GLenum target,
GLint level,
GLenum internalformat,
GLint x,
GLint y,
GLsizei width,
GLsizei height,
GLint border)
{
if (context->getClientVersion() < 3)
{
return ValidateES2CopyTexImageParameters(context, target, level, internalformat, false, 0,
0, x, y, width, height, border);
}
ASSERT(context->getClientVersion() == 3);
return ValidateES3CopyTexImageParameters(context, target, level, internalformat, false, 0, 0, 0,
x, y, width, height, border);
} }
bool ValidateFramebufferRenderbuffer(Context *context,
GLenum target,
GLenum attachment,
GLenum renderbuffertarget,
GLuint renderbuffer)
{
if (!ValidFramebufferTarget(target) ||
(renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0))
{
context->recordError(Error(GL_INVALID_ENUM));
return false;
}
return ValidateFramebufferRenderbufferParameters(context, target, attachment,
renderbuffertarget, renderbuffer);
}
bool ValidateDrawBuffersBase(ValidationContext *context, GLsizei n, const GLenum *bufs)
{
// INVALID_VALUE is generated if n is negative or greater than value of MAX_DRAW_BUFFERS
if (n < 0 || static_cast<GLuint>(n) > context->getCaps().maxDrawBuffers)
{
context->recordError(
Error(GL_INVALID_VALUE, "n must be non-negative and no greater than MAX_DRAW_BUFFERS"));
return false;
}
ASSERT(context->getState().getDrawFramebuffer());
GLuint frameBufferId = context->getState().getDrawFramebuffer()->id();
GLuint maxColorAttachment = GL_COLOR_ATTACHMENT0_EXT + context->getCaps().maxColorAttachments;
// This should come first before the check for the default frame buffer
// because when we switch to ES3.1+, invalid enums will return INVALID_ENUM
// rather than INVALID_OPERATION
for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
{
const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != GL_BACK &&
(bufs[colorAttachment] < GL_COLOR_ATTACHMENT0_EXT ||
bufs[colorAttachment] >= maxColorAttachment))
{
// Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi
// In the 3.0 specs, the error should return GL_INVALID_OPERATION.
// When we move to 3.1 specs, we should change the error to be GL_INVALID_ENUM
context->recordError(Error(GL_INVALID_OPERATION, "Invalid buffer value"));
return false;
}
else if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment &&
frameBufferId != 0)
{
// INVALID_OPERATION-GL is bound to buffer and ith argument
// is not COLOR_ATTACHMENTi or NONE
context->recordError(
Error(GL_INVALID_OPERATION, "Ith value does not match COLOR_ATTACHMENTi or NONE"));
return false;
}
}
// INVALID_OPERATION is generated if GL is bound to the default framebuffer
// and n is not 1 or bufs is bound to value other than BACK and NONE
if (frameBufferId == 0)
{
if (n != 1)
{
context->recordError(Error(GL_INVALID_OPERATION,
"n must be 1 when GL is bound to the default framebuffer"));
return false;
}
if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
{
context->recordError(Error(
GL_INVALID_OPERATION,
"Only NONE or BACK are valid values when drawing to the default framebuffer"));
return false;
}
}
return true;
}
bool ValidateCopyTexSubImage2D(Context *context,
GLenum target,
GLint level,
GLint xoffset,
GLint yoffset,
GLint x,
GLint y,
GLsizei width,
GLsizei height)
{
if (context->getClientVersion() < 3)
{
return ValidateES2CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset,
yoffset, x, y, width, height, 0);
}
return ValidateES3CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset,
yoffset, 0, x, y, width, height, 0);
}
} // namespace gl
...@@ -22,7 +22,6 @@ class Image; ...@@ -22,7 +22,6 @@ class Image;
namespace gl namespace gl
{ {
class Context; class Context;
class Program; class Program;
class Shader; class Shader;
...@@ -30,11 +29,11 @@ class ValidationContext; ...@@ -30,11 +29,11 @@ class ValidationContext;
bool ValidCap(const Context *context, GLenum cap); bool ValidCap(const Context *context, GLenum cap);
bool ValidTextureTarget(const Context *context, GLenum target); bool ValidTextureTarget(const Context *context, GLenum target);
bool ValidTexture2DDestinationTarget(const Context *context, GLenum target); bool ValidTexture2DDestinationTarget(const ValidationContext *context, GLenum target);
bool ValidFramebufferTarget(GLenum target); bool ValidFramebufferTarget(GLenum target);
bool ValidBufferTarget(const Context *context, GLenum target); bool ValidBufferTarget(const Context *context, GLenum target);
bool ValidBufferParameter(const Context *context, GLenum pname); bool ValidBufferParameter(const Context *context, GLenum pname);
bool ValidMipLevel(const Context *context, GLenum target, GLint level); bool ValidMipLevel(const ValidationContext *context, GLenum target, GLint level);
bool ValidImageSizeParameters(const Context *context, bool ValidImageSizeParameters(const Context *context,
GLenum target, GLenum target,
GLint level, GLint level,
...@@ -42,7 +41,10 @@ bool ValidImageSizeParameters(const Context *context, ...@@ -42,7 +41,10 @@ bool ValidImageSizeParameters(const Context *context,
GLsizei height, GLsizei height,
GLsizei depth, GLsizei depth,
bool isSubImage); bool isSubImage);
bool ValidCompressedImageSize(const Context *context, GLenum internalFormat, GLsizei width, GLsizei height); bool ValidCompressedImageSize(const ValidationContext *context,
GLenum internalFormat,
GLsizei width,
GLsizei height);
bool ValidQueryType(const Context *context, GLenum queryType); bool ValidQueryType(const Context *context, GLenum queryType);
// Returns valid program if id is a valid program name // Returns valid program if id is a valid program name
...@@ -64,9 +66,17 @@ bool ValidateRenderbufferStorageParametersANGLE(Context *context, GLenum target, ...@@ -64,9 +66,17 @@ bool ValidateRenderbufferStorageParametersANGLE(Context *context, GLenum target,
bool ValidateFramebufferRenderbufferParameters(Context *context, GLenum target, GLenum attachment, bool ValidateFramebufferRenderbufferParameters(Context *context, GLenum target, GLenum attachment,
GLenum renderbuffertarget, GLuint renderbuffer); GLenum renderbuffertarget, GLuint renderbuffer);
bool ValidateBlitFramebufferParameters(Context *context, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, bool ValidateBlitFramebufferParameters(Context *context,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLint srcX0,
GLenum filter, bool fromAngleExtension); GLint srcY0,
GLint srcX1,
GLint srcY1,
GLint dstX0,
GLint dstY0,
GLint dstX1,
GLint dstY1,
GLbitfield mask,
GLenum filter);
bool ValidateGetVertexAttribParameters(Context *context, GLenum pname); bool ValidateGetVertexAttribParameters(Context *context, GLenum pname);
...@@ -74,8 +84,23 @@ bool ValidateTexParamParameters(Context *context, GLenum pname, GLint param); ...@@ -74,8 +84,23 @@ bool ValidateTexParamParameters(Context *context, GLenum pname, GLint param);
bool ValidateSamplerObjectParameter(Context *context, GLenum pname); bool ValidateSamplerObjectParameter(Context *context, GLenum pname);
bool ValidateReadPixelsParameters(Context *context, GLint x, GLint y, GLsizei width, GLsizei height, bool ValidateReadPixels(Context *context,
GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels); GLint x,
GLint y,
GLsizei width,
GLsizei height,
GLenum format,
GLenum type,
GLvoid *pixels);
bool ValidateReadnPixelsEXT(Context *context,
GLint x,
GLint y,
GLsizei width,
GLsizei height,
GLenum format,
GLenum type,
GLsizei bufSize,
GLvoid *pixels);
bool ValidateBeginQuery(Context *context, GLenum target, GLuint id); bool ValidateBeginQuery(Context *context, GLenum target, GLuint id);
bool ValidateEndQuery(Context *context, GLenum target); bool ValidateEndQuery(Context *context, GLenum target);
...@@ -86,9 +111,20 @@ bool ValidateUniformMatrix(Context *context, GLenum matrixType, GLint location, ...@@ -86,9 +111,20 @@ bool ValidateUniformMatrix(Context *context, GLenum matrixType, GLint location,
bool ValidateStateQuery(Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams); bool ValidateStateQuery(Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams);
bool ValidateCopyTexImageParametersBase(Context *context, GLenum target, GLint level, GLenum internalformat, bool isSubImage, bool ValidateCopyTexImageParametersBase(ValidationContext *context,
GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, GLenum target,
GLint border, GLenum *textureInternalFormatOut); GLint level,
GLenum internalformat,
bool isSubImage,
GLint xoffset,
GLint yoffset,
GLint zoffset,
GLint x,
GLint y,
GLsizei width,
GLsizei height,
GLint border,
GLenum *textureInternalFormatOut);
bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount); bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount);
bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount); bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount);
...@@ -121,6 +157,11 @@ bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum atta ...@@ -121,6 +157,11 @@ bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum atta
GLuint texture, GLint level); GLuint texture, GLint level);
bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment, bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
GLenum textarget, GLuint texture, GLint level); GLenum textarget, GLuint texture, GLint level);
bool ValidateFramebufferRenderbuffer(Context *context,
GLenum target,
GLenum attachment,
GLenum renderbuffertarget,
GLuint renderbuffer);
bool ValidateGetUniformBase(Context *context, GLuint program, GLint location); bool ValidateGetUniformBase(Context *context, GLuint program, GLint location);
bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params); bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params);
...@@ -159,8 +200,28 @@ bool ValidateGetProgramBinaryBase(Context *context, ...@@ -159,8 +200,28 @@ bool ValidateGetProgramBinaryBase(Context *context,
GLenum *binaryFormat, GLenum *binaryFormat,
void *binary); void *binary);
bool ValidateCopyTexImage2D(ValidationContext *context,
GLenum target,
GLint level,
GLenum internalformat,
GLint x,
GLint y,
GLsizei width,
GLsizei height,
GLint border);
bool ValidateDrawBuffersBase(ValidationContext *context, GLsizei n, const GLenum *bufs);
bool ValidateCopyTexSubImage2D(Context *context,
GLenum target,
GLint level,
GLint xoffset,
GLint yoffset,
GLint x,
GLint y,
GLsizei width,
GLsizei height);
// Error messages shared here for use in testing. // Error messages shared here for use in testing.
extern const char *g_ExceedsMaxElementErrorMessage; extern const char *g_ExceedsMaxElementErrorMessage;
} } // namespace gl
#endif // LIBANGLE_VALIDATION_ES_H_ #endif // LIBANGLE_VALIDATION_ES_H_
...@@ -21,6 +21,42 @@ ...@@ -21,6 +21,42 @@
namespace gl namespace gl
{ {
namespace
{
bool IsPartialBlit(gl::Context *context,
const FramebufferAttachment *readBuffer,
const FramebufferAttachment *writeBuffer,
GLint srcX0,
GLint srcY0,
GLint srcX1,
GLint srcY1,
GLint dstX0,
GLint dstY0,
GLint dstX1,
GLint dstY1)
{
const Extents &writeSize = writeBuffer->getSize();
const Extents &readSize = readBuffer->getSize();
if (srcX0 != 0 || srcY0 != 0 || dstX0 != 0 || dstY0 != 0 || dstX1 != writeSize.width ||
dstY1 != writeSize.height || srcX1 != readSize.width || srcY1 != readSize.height)
{
return true;
}
if (context->getState().isScissorTestEnabled())
{
const Rectangle &scissor = context->getState().getScissor();
return scissor.x > 0 || scissor.y > 0 || scissor.width < writeSize.width ||
scissor.height < writeSize.height;
}
return false;
}
} // anonymous namespace
bool ValidateES2TexImageParameters(Context *context, GLenum target, GLint level, GLenum internalformat, bool isCompressed, bool isSubImage, bool ValidateES2TexImageParameters(Context *context, GLenum target, GLint level, GLenum internalformat, bool isCompressed, bool isSubImage,
GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
GLint border, GLenum format, GLenum type, const GLvoid *pixels) GLint border, GLenum format, GLenum type, const GLvoid *pixels)
...@@ -407,10 +443,17 @@ bool ValidateES2TexImageParameters(Context *context, GLenum target, GLint level, ...@@ -407,10 +443,17 @@ bool ValidateES2TexImageParameters(Context *context, GLenum target, GLint level,
return true; return true;
} }
bool ValidateES2CopyTexImageParameters(ValidationContext *context,
GLenum target,
bool ValidateES2CopyTexImageParameters(Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage, GLint level,
GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, GLenum internalformat,
bool isSubImage,
GLint xoffset,
GLint yoffset,
GLint x,
GLint y,
GLsizei width,
GLsizei height,
GLint border) GLint border)
{ {
GLenum textureInternalFormat = GL_NONE; GLenum textureInternalFormat = GL_NONE;
...@@ -421,7 +464,7 @@ bool ValidateES2CopyTexImageParameters(Context* context, GLenum target, GLint le ...@@ -421,7 +464,7 @@ bool ValidateES2CopyTexImageParameters(Context* context, GLenum target, GLint le
return false; return false;
} }
gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer(); const gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
GLenum colorbufferFormat = framebuffer->getReadColorbuffer()->getInternalFormat(); GLenum colorbufferFormat = framebuffer->getReadColorbuffer()->getInternalFormat();
const auto &internalFormatInfo = gl::GetInternalFormatInfo(textureInternalFormat); const auto &internalFormatInfo = gl::GetInternalFormatInfo(textureInternalFormat);
GLenum textureFormat = internalFormatInfo.format; GLenum textureFormat = internalFormatInfo.format;
...@@ -914,6 +957,12 @@ bool ValidES2ReadFormatType(Context *context, GLenum format, GLenum type) ...@@ -914,6 +957,12 @@ bool ValidES2ReadFormatType(Context *context, GLenum format, GLenum type)
bool ValidateDiscardFramebufferEXT(Context *context, GLenum target, GLsizei numAttachments, bool ValidateDiscardFramebufferEXT(Context *context, GLenum target, GLsizei numAttachments,
const GLenum *attachments) const GLenum *attachments)
{ {
if (!context->getExtensions().discardFramebuffer)
{
context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled"));
return false;
}
bool defaultFramebuffer = false; bool defaultFramebuffer = false;
switch (target) switch (target)
...@@ -929,71 +978,6 @@ bool ValidateDiscardFramebufferEXT(Context *context, GLenum target, GLsizei numA ...@@ -929,71 +978,6 @@ bool ValidateDiscardFramebufferEXT(Context *context, GLenum target, GLsizei numA
return ValidateDiscardFramebufferBase(context, target, numAttachments, attachments, defaultFramebuffer); return ValidateDiscardFramebufferBase(context, target, numAttachments, attachments, defaultFramebuffer);
} }
bool ValidateDrawBuffers(Context *context, GLsizei n, const GLenum *bufs)
{
// INVALID_VALUE is generated if n is negative or greater than value of MAX_DRAW_BUFFERS
if (n < 0 || static_cast<GLuint>(n) > context->getCaps().maxDrawBuffers)
{
context->recordError(
Error(GL_INVALID_VALUE, "n must be non-negative and no greater than MAX_DRAW_BUFFERS"));
return false;
}
ASSERT(context->getState().getDrawFramebuffer());
GLuint frameBufferId = context->getState().getDrawFramebuffer()->id();
GLuint maxColorAttachment = GL_COLOR_ATTACHMENT0_EXT + context->getCaps().maxColorAttachments;
// This should come first before the check for the default frame buffer
// because when we switch to ES3.1+, invalid enums will return INVALID_ENUM
// rather than INVALID_OPERATION
for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
{
const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != GL_BACK &&
(bufs[colorAttachment] < GL_COLOR_ATTACHMENT0_EXT ||
bufs[colorAttachment] >= maxColorAttachment))
{
// Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi
// In the 3.0 specs, the error should return GL_INVALID_OPERATION.
// When we move to 3.1 specs, we should change the error to be GL_INVALID_ENUM
context->recordError(Error(GL_INVALID_OPERATION, "Invalid buffer value"));
return false;
}
else if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment &&
frameBufferId != 0)
{
// INVALID_OPERATION-GL is bound to buffer and ith argument
// is not COLOR_ATTACHMENTi or NONE
context->recordError(
Error(GL_INVALID_OPERATION, "Ith value does not match COLOR_ATTACHMENTi or NONE"));
return false;
}
}
// INVALID_OPERATION is generated if GL is bound to the default framebuffer
// and n is not 1 or bufs is bound to value other than BACK and NONE
if (frameBufferId == 0)
{
if (n != 1)
{
context->recordError(Error(GL_INVALID_OPERATION,
"n must be 1 when GL is bound to the default framebuffer"));
return false;
}
if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
{
context->recordError(Error(
GL_INVALID_OPERATION,
"Only NONE or BACK are valid values when drawing to the default framebuffer"));
return false;
}
}
return true;
}
bool ValidateBindVertexArrayOES(Context *context, GLuint array) bool ValidateBindVertexArrayOES(Context *context, GLuint array)
{ {
if (!context->getExtensions().vertexArrayObject) if (!context->getExtensions().vertexArrayObject)
...@@ -1559,4 +1543,164 @@ bool ValidateGetPointervKHR(Context *context, GLenum pname, void **params) ...@@ -1559,4 +1543,164 @@ bool ValidateGetPointervKHR(Context *context, GLenum pname, void **params)
return true; return true;
} }
bool ValidateBlitFramebufferANGLE(Context *context,
GLint srcX0,
GLint srcY0,
GLint srcX1,
GLint srcY1,
GLint dstX0,
GLint dstY0,
GLint dstX1,
GLint dstY1,
GLbitfield mask,
GLenum filter)
{
if (!context->getExtensions().framebufferBlit)
{
context->recordError(Error(GL_INVALID_OPERATION, "Blit extension not available."));
return false;
}
if (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0)
{
// TODO(jmadill): Determine if this should be available on other implementations.
context->recordError(Error(
GL_INVALID_OPERATION,
"Scaling and flipping in BlitFramebufferANGLE not supported by this implementation."));
return false;
}
if (filter == GL_LINEAR)
{
context->recordError(Error(GL_INVALID_ENUM, "Linear blit not supported in this extension"));
return false;
}
const Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
const Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer();
if (mask & GL_COLOR_BUFFER_BIT)
{
const FramebufferAttachment *readColorAttachment = readFramebuffer->getReadColorbuffer();
const FramebufferAttachment *drawColorAttachment = drawFramebuffer->getFirstColorbuffer();
if (readColorAttachment && drawColorAttachment)
{
if (!(readColorAttachment->type() == GL_TEXTURE &&
readColorAttachment->getTextureImageIndex().type == GL_TEXTURE_2D) &&
readColorAttachment->type() != GL_RENDERBUFFER &&
readColorAttachment->type() != GL_FRAMEBUFFER_DEFAULT)
{
context->recordError(Error(GL_INVALID_OPERATION));
return false;
}
for (size_t colorAttachment = 0;
colorAttachment < drawFramebuffer->getNumColorBuffers(); ++colorAttachment)
{
if (drawFramebuffer->isEnabledColorAttachment(colorAttachment))
{
const FramebufferAttachment *attachment =
drawFramebuffer->getColorbuffer(colorAttachment);
ASSERT(attachment);
if (!(attachment->type() == GL_TEXTURE &&
attachment->getTextureImageIndex().type == GL_TEXTURE_2D) &&
attachment->type() != GL_RENDERBUFFER &&
attachment->type() != GL_FRAMEBUFFER_DEFAULT)
{
context->recordError(Error(GL_INVALID_OPERATION));
return false;
}
// Return an error if the destination formats do not match
if (attachment->getInternalFormat() != readColorAttachment->getInternalFormat())
{
context->recordError(Error(GL_INVALID_OPERATION));
return false;
}
}
}
int readSamples = readFramebuffer->getSamples(context->getData());
if (readSamples != 0 &&
IsPartialBlit(context, readColorAttachment, drawColorAttachment, srcX0, srcY0,
srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
{
context->recordError(Error(GL_INVALID_OPERATION));
return false;
}
}
}
GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
for (size_t i = 0; i < 2; i++)
{
if (mask & masks[i])
{
const FramebufferAttachment *readBuffer =
readFramebuffer->getAttachment(attachments[i]);
const FramebufferAttachment *drawBuffer =
drawFramebuffer->getAttachment(attachments[i]);
if (readBuffer && drawBuffer)
{
if (IsPartialBlit(context, readBuffer, drawBuffer, srcX0, srcY0, srcX1, srcY1,
dstX0, dstY0, dstX1, dstY1))
{
// only whole-buffer copies are permitted
ERR(
"Only whole-buffer depth and stencil blits are supported by this "
"implementation.");
context->recordError(Error(GL_INVALID_OPERATION));
return false;
}
if (readBuffer->getSamples() != 0 || drawBuffer->getSamples() != 0)
{
context->recordError(Error(GL_INVALID_OPERATION));
return false;
}
}
}
}
return ValidateBlitFramebufferParameters(context, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0,
dstX1, dstY1, mask, filter);
} }
bool ValidateClear(ValidationContext *context, GLbitfield mask)
{
const Framebuffer *framebufferObject = context->getState().getDrawFramebuffer();
ASSERT(framebufferObject);
if (framebufferObject->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
{
context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
return false;
}
if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) != 0)
{
context->recordError(Error(GL_INVALID_VALUE));
return false;
}
return true;
}
bool ValidateDrawBuffersEXT(ValidationContext *context, GLsizei n, const GLenum *bufs)
{
if (!context->getExtensions().drawBuffers)
{
context->recordError(Error(GL_INVALID_OPERATION, "Extension not supported."));
return false;
}
return ValidateDrawBuffersBase(context, n, bufs);
}
} // namespace gl
...@@ -14,15 +14,24 @@ ...@@ -14,15 +14,24 @@
namespace gl namespace gl
{ {
class Context; class Context;
class ValidationContext;
bool ValidateES2TexImageParameters(Context *context, GLenum target, GLint level, GLenum internalformat, bool isCompressed, bool isSubImage, bool ValidateES2TexImageParameters(Context *context, GLenum target, GLint level, GLenum internalformat, bool isCompressed, bool isSubImage,
GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
GLint border, GLenum format, GLenum type, const GLvoid *pixels); GLint border, GLenum format, GLenum type, const GLvoid *pixels);
bool ValidateES2CopyTexImageParameters(Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage, bool ValidateES2CopyTexImageParameters(ValidationContext *context,
GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, GLenum target,
GLint level,
GLenum internalformat,
bool isSubImage,
GLint xoffset,
GLint yoffset,
GLint x,
GLint y,
GLsizei width,
GLsizei height,
GLint border); GLint border);
bool ValidateES2TexStorageParameters(Context *context, GLenum target, GLsizei levels, GLenum internalformat, bool ValidateES2TexStorageParameters(Context *context, GLenum target, GLsizei levels, GLenum internalformat,
...@@ -33,7 +42,7 @@ bool ValidES2ReadFormatType(Context *context, GLenum format, GLenum type); ...@@ -33,7 +42,7 @@ bool ValidES2ReadFormatType(Context *context, GLenum format, GLenum type);
bool ValidateDiscardFramebufferEXT(Context *context, GLenum target, GLsizei numAttachments, bool ValidateDiscardFramebufferEXT(Context *context, GLenum target, GLsizei numAttachments,
const GLenum *attachments); const GLenum *attachments);
bool ValidateDrawBuffers(Context *context, GLsizei n, const GLenum *bufs); bool ValidateDrawBuffersEXT(ValidationContext *context, GLsizei n, const GLenum *bufs);
bool ValidateBindVertexArrayOES(Context *context, GLuint array); bool ValidateBindVertexArrayOES(Context *context, GLuint array);
bool ValidateDeleteVertexArraysOES(Context *context, GLsizei n); bool ValidateDeleteVertexArraysOES(Context *context, GLsizei n);
...@@ -106,6 +115,20 @@ bool ValidateGetObjectPtrLabelKHR(Context *context, ...@@ -106,6 +115,20 @@ bool ValidateGetObjectPtrLabelKHR(Context *context,
GLsizei *length, GLsizei *length,
GLchar *label); GLchar *label);
bool ValidateGetPointervKHR(Context *context, GLenum pname, void **params); bool ValidateGetPointervKHR(Context *context, GLenum pname, void **params);
} bool ValidateBlitFramebufferANGLE(Context *context,
GLint srcX0,
GLint srcY0,
GLint srcX1,
GLint srcY1,
GLint dstX0,
GLint dstY0,
GLint dstX1,
GLint dstY1,
GLbitfield mask,
GLenum filter);
bool ValidateClear(ValidationContext *context, GLbitfield mask);
} // namespace gl
#endif // LIBANGLE_VALIDATION_ES2_H_ #endif // LIBANGLE_VALIDATION_ES2_H_
...@@ -786,9 +786,19 @@ static bool IsValidES3CopyTexImageCombination(GLenum textureInternalFormat, GLen ...@@ -786,9 +786,19 @@ static bool IsValidES3CopyTexImageCombination(GLenum textureInternalFormat, GLen
return false; return false;
} }
bool ValidateES3CopyTexImageParameters(Context *context, GLenum target, GLint level, GLenum internalformat, bool ValidateES3CopyTexImageParameters(ValidationContext *context,
bool isSubImage, GLint xoffset, GLint yoffset, GLint zoffset, GLenum target,
GLint x, GLint y, GLsizei width, GLsizei height, GLint border) GLint level,
GLenum internalformat,
bool isSubImage,
GLint xoffset,
GLint yoffset,
GLint zoffset,
GLint x,
GLint y,
GLsizei width,
GLsizei height,
GLint border)
{ {
GLenum textureInternalFormat; GLenum textureInternalFormat;
if (!ValidateCopyTexImageParametersBase(context, target, level, internalformat, isSubImage, if (!ValidateCopyTexImageParametersBase(context, target, level, internalformat, isSubImage,
...@@ -798,7 +808,9 @@ bool ValidateES3CopyTexImageParameters(Context *context, GLenum target, GLint le ...@@ -798,7 +808,9 @@ bool ValidateES3CopyTexImageParameters(Context *context, GLenum target, GLint le
return false; return false;
} }
gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer(); const auto &state = context->getState();
const gl::Framebuffer *framebuffer = state.getReadFramebuffer();
GLuint readFramebufferID = framebuffer->id();
if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE) if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
{ {
...@@ -806,8 +818,7 @@ bool ValidateES3CopyTexImageParameters(Context *context, GLenum target, GLint le ...@@ -806,8 +818,7 @@ bool ValidateES3CopyTexImageParameters(Context *context, GLenum target, GLint le
return false; return false;
} }
if (context->getState().getReadFramebuffer()->id() != 0 && if (readFramebufferID != 0 && framebuffer->getSamples(context->getData()) != 0)
framebuffer->getSamples(context->getData()) != 0)
{ {
context->recordError(Error(GL_INVALID_OPERATION)); context->recordError(Error(GL_INVALID_OPERATION));
return false; return false;
...@@ -819,7 +830,7 @@ bool ValidateES3CopyTexImageParameters(Context *context, GLenum target, GLint le ...@@ -819,7 +830,7 @@ bool ValidateES3CopyTexImageParameters(Context *context, GLenum target, GLint le
if (isSubImage) if (isSubImage)
{ {
if (!IsValidES3CopyTexImageCombination(textureInternalFormat, colorbufferInternalFormat, if (!IsValidES3CopyTexImageCombination(textureInternalFormat, colorbufferInternalFormat,
context->getState().getReadFramebuffer()->id())) readFramebufferID))
{ {
context->recordError(Error(GL_INVALID_OPERATION)); context->recordError(Error(GL_INVALID_OPERATION));
return false; return false;
...@@ -828,7 +839,7 @@ bool ValidateES3CopyTexImageParameters(Context *context, GLenum target, GLint le ...@@ -828,7 +839,7 @@ bool ValidateES3CopyTexImageParameters(Context *context, GLenum target, GLint le
else else
{ {
if (!gl::IsValidES3CopyTexImageCombination(internalformat, colorbufferInternalFormat, if (!gl::IsValidES3CopyTexImageCombination(internalformat, colorbufferInternalFormat,
context->getState().getReadFramebuffer()->id())) readFramebufferID))
{ {
context->recordError(Error(GL_INVALID_OPERATION)); context->recordError(Error(GL_INVALID_OPERATION));
return false; return false;
...@@ -1157,7 +1168,7 @@ bool ValidateInvalidateFramebuffer(Context *context, GLenum target, GLsizei numA ...@@ -1157,7 +1168,7 @@ bool ValidateInvalidateFramebuffer(Context *context, GLenum target, GLsizei numA
return ValidateDiscardFramebufferBase(context, target, numAttachments, attachments, defaultFramebuffer); return ValidateDiscardFramebufferBase(context, target, numAttachments, attachments, defaultFramebuffer);
} }
bool ValidateClearBuffer(Context *context) bool ValidateClearBuffer(ValidationContext *context)
{ {
if (context->getClientVersion() < 3) if (context->getClientVersion() < 3)
{ {
...@@ -1381,4 +1392,171 @@ bool ValidateProgramParameter(Context *context, GLuint program, GLenum pname, GL ...@@ -1381,4 +1392,171 @@ bool ValidateProgramParameter(Context *context, GLuint program, GLenum pname, GL
return true; return true;
} }
bool ValidateBlitFramebuffer(Context *context,
GLint srcX0,
GLint srcY0,
GLint srcX1,
GLint srcY1,
GLint dstX0,
GLint dstY0,
GLint dstX1,
GLint dstY1,
GLbitfield mask,
GLenum filter)
{
if (context->getClientVersion() < 3)
{
context->recordError(Error(GL_INVALID_OPERATION));
return false;
}
return ValidateBlitFramebufferParameters(context, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0,
dstX1, dstY1, mask, filter);
}
bool ValidateClearBufferiv(ValidationContext *context,
GLenum buffer,
GLint drawbuffer,
const GLint *value)
{
switch (buffer)
{
case GL_COLOR:
if (drawbuffer < 0 ||
static_cast<GLuint>(drawbuffer) >= context->getCaps().maxDrawBuffers)
{
context->recordError(Error(GL_INVALID_VALUE));
return false;
}
break;
case GL_STENCIL:
if (drawbuffer != 0)
{
context->recordError(Error(GL_INVALID_VALUE));
return false;
}
break;
default:
context->recordError(Error(GL_INVALID_ENUM));
return false;
}
return ValidateClearBuffer(context);
}
bool ValidateClearBufferuiv(ValidationContext *context,
GLenum buffer,
GLint drawbuffer,
const GLuint *value)
{
switch (buffer)
{
case GL_COLOR:
if (drawbuffer < 0 ||
static_cast<GLuint>(drawbuffer) >= context->getCaps().maxDrawBuffers)
{
context->recordError(Error(GL_INVALID_VALUE));
return false;
}
break;
default:
context->recordError(Error(GL_INVALID_ENUM));
return false;
}
return ValidateClearBuffer(context);
}
bool ValidateClearBufferfv(ValidationContext *context,
GLenum buffer,
GLint drawbuffer,
const GLfloat *value)
{
switch (buffer)
{
case GL_COLOR:
if (drawbuffer < 0 ||
static_cast<GLuint>(drawbuffer) >= context->getCaps().maxDrawBuffers)
{
context->recordError(Error(GL_INVALID_VALUE));
return false;
}
break;
case GL_DEPTH:
if (drawbuffer != 0)
{
context->recordError(Error(GL_INVALID_VALUE));
return false;
}
break;
default:
context->recordError(Error(GL_INVALID_ENUM));
return false;
}
return ValidateClearBuffer(context);
} }
bool ValidateClearBufferfi(ValidationContext *context,
GLenum buffer,
GLint drawbuffer,
GLfloat depth,
GLint stencil)
{
switch (buffer)
{
case GL_DEPTH_STENCIL:
if (drawbuffer != 0)
{
context->recordError(Error(GL_INVALID_VALUE));
return false;
}
break;
default:
context->recordError(Error(GL_INVALID_ENUM));
return false;
}
return ValidateClearBuffer(context);
}
bool ValidateDrawBuffers(ValidationContext *context, GLsizei n, const GLenum *bufs)
{
if (context->getClientVersion() < 3)
{
context->recordError(Error(GL_INVALID_OPERATION, "Context does not support GLES3."));
return false;
}
return ValidateDrawBuffersBase(context, n, bufs);
}
bool ValidateCopyTexSubImage3D(Context *context,
GLenum target,
GLint level,
GLint xoffset,
GLint yoffset,
GLint zoffset,
GLint x,
GLint y,
GLsizei width,
GLsizei height)
{
if (context->getClientVersion() < 3)
{
context->recordError(Error(GL_INVALID_OPERATION));
return false;
}
return ValidateES3CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset,
yoffset, zoffset, x, y, width, height, 0);
}
} // namespace gl
...@@ -13,16 +13,26 @@ ...@@ -13,16 +13,26 @@
namespace gl namespace gl
{ {
class Context; class Context;
class ValidationContext;
bool ValidateES3TexImageParameters(Context *context, GLenum target, GLint level, GLenum internalformat, bool isCompressed, bool isSubImage, bool ValidateES3TexImageParameters(Context *context, GLenum target, GLint level, GLenum internalformat, bool isCompressed, bool isSubImage,
GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
GLint border, GLenum format, GLenum type, const GLvoid *pixels); GLint border, GLenum format, GLenum type, const GLvoid *pixels);
bool ValidateES3CopyTexImageParameters(Context *context, GLenum target, GLint level, GLenum internalformat, bool ValidateES3CopyTexImageParameters(ValidationContext *context,
bool isSubImage, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLenum target,
GLsizei width, GLsizei height, GLint border); GLint level,
GLenum internalformat,
bool isSubImage,
GLint xoffset,
GLint yoffset,
GLint zoffset,
GLint x,
GLint y,
GLsizei width,
GLsizei height,
GLint border);
bool ValidateES3TexStorageParameters(Context *context, GLenum target, GLsizei levels, GLenum internalformat, bool ValidateES3TexStorageParameters(Context *context, GLenum target, GLsizei levels, GLenum internalformat,
GLsizei width, GLsizei height, GLsizei depth); GLsizei width, GLsizei height, GLsizei depth);
...@@ -38,7 +48,7 @@ bool ValidateES3RenderbufferStorageParameters(Context *context, GLenum target, G ...@@ -38,7 +48,7 @@ bool ValidateES3RenderbufferStorageParameters(Context *context, GLenum target, G
bool ValidateInvalidateFramebuffer(Context *context, GLenum target, GLsizei numAttachments, bool ValidateInvalidateFramebuffer(Context *context, GLenum target, GLsizei numAttachments,
const GLenum *attachments); const GLenum *attachments);
bool ValidateClearBuffer(Context *context); bool ValidateClearBuffer(ValidationContext *context);
bool ValidateGetUniformuiv(Context *context, GLuint program, GLint location, GLuint* params); bool ValidateGetUniformuiv(Context *context, GLuint program, GLint location, GLuint* params);
...@@ -72,6 +82,46 @@ bool ValidateGetProgramBinary(Context *context, ...@@ -72,6 +82,46 @@ bool ValidateGetProgramBinary(Context *context,
GLenum *binaryFormat, GLenum *binaryFormat,
void *binary); void *binary);
bool ValidateProgramParameter(Context *context, GLuint program, GLenum pname, GLint value); bool ValidateProgramParameter(Context *context, GLuint program, GLenum pname, GLint value);
} bool ValidateBlitFramebuffer(Context *context,
GLint srcX0,
GLint srcY0,
GLint srcX1,
GLint srcY1,
GLint dstX0,
GLint dstY0,
GLint dstX1,
GLint dstY1,
GLbitfield mask,
GLenum filter);
bool ValidateClearBufferiv(ValidationContext *context,
GLenum buffer,
GLint drawbuffer,
const GLint *value);
bool ValidateClearBufferuiv(ValidationContext *context,
GLenum buffer,
GLint drawbuffer,
const GLuint *value);
bool ValidateClearBufferfv(ValidationContext *context,
GLenum buffer,
GLint drawbuffer,
const GLfloat *value);
bool ValidateClearBufferfi(ValidationContext *context,
GLenum buffer,
GLint drawbuffer,
GLfloat depth,
GLint stencil);
bool ValidateDrawBuffers(ValidationContext *context, GLsizei n, const GLenum *bufs);
bool ValidateCopyTexSubImage3D(Context *context,
GLenum target,
GLint level,
GLint xoffset,
GLint yoffset,
GLint zoffset,
GLint x,
GLint y,
GLsizei width,
GLsizei height);
} // namespace gl
#endif // LIBANGLE_VALIDATION_ES3_H_ #endif // LIBANGLE_VALIDATION_ES3_H_
...@@ -593,27 +593,12 @@ void GL_APIENTRY Clear(GLbitfield mask) ...@@ -593,27 +593,12 @@ void GL_APIENTRY Clear(GLbitfield mask)
Context *context = GetValidGlobalContext(); Context *context = GetValidGlobalContext();
if (context) if (context)
{ {
Framebuffer *framebufferObject = context->getState().getDrawFramebuffer(); if (!context->skipValidation() && !ValidateClear(context, mask))
ASSERT(framebufferObject);
if (framebufferObject->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
{
context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
return;
}
if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) != 0)
{ {
context->recordError(Error(GL_INVALID_VALUE));
return; return;
} }
Error error = framebufferObject->clear(context, mask); context->clear(mask);
if (error.isError())
{
context->recordError(error);
return;
}
} }
} }
...@@ -777,30 +762,13 @@ void GL_APIENTRY CopyTexImage2D(GLenum target, GLint level, GLenum internalforma ...@@ -777,30 +762,13 @@ void GL_APIENTRY CopyTexImage2D(GLenum target, GLint level, GLenum internalforma
Context *context = GetValidGlobalContext(); Context *context = GetValidGlobalContext();
if (context) if (context)
{ {
if (context->getClientVersion() < 3 && if (!context->skipValidation() &&
!ValidateES2CopyTexImageParameters(context, target, level, internalformat, false, !ValidateCopyTexImage2D(context, target, level, internalformat, x, y, width, height,
0, 0, x, y, width, height, border)) border))
{
return;
}
if (context->getClientVersion() >= 3 &&
!ValidateES3CopyTexImageParameters(context, target, level, internalformat, false,
0, 0, 0, x, y, width, height, border))
{
return;
}
Rectangle sourceArea(x, y, width, height);
const Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Error error = texture->copyImage(target, level, sourceArea, internalformat, framebuffer);
if (error.isError())
{ {
context->recordError(error);
return; return;
} }
context->copyTexImage2D(target, level, internalformat, x, y, width, height, border);
} }
} }
...@@ -813,31 +781,14 @@ void GL_APIENTRY CopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GL ...@@ -813,31 +781,14 @@ void GL_APIENTRY CopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GL
Context *context = GetValidGlobalContext(); Context *context = GetValidGlobalContext();
if (context) if (context)
{ {
if (context->getClientVersion() < 3 && if (!context->skipValidation() &&
!ValidateES2CopyTexImageParameters(context, target, level, GL_NONE, true, !ValidateCopyTexSubImage2D(context, target, level, xoffset, yoffset, x, y, width,
xoffset, yoffset, x, y, width, height, 0)) height))
{
return;
}
if (context->getClientVersion() >= 3 &&
!ValidateES3CopyTexImageParameters(context, target, level, GL_NONE, true,
xoffset, yoffset, 0, x, y, width, height, 0))
{ {
return; return;
} }
Offset destOffset(xoffset, yoffset, 0); context->copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
Rectangle sourceArea(x, y, width, height);
const Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Error error = texture->copySubImage(target, level, destOffset, sourceArea, framebuffer);
if (error.isError())
{
context->recordError(error);
return;
}
} }
} }
...@@ -1287,29 +1238,14 @@ void GL_APIENTRY FramebufferRenderbuffer(GLenum target, GLenum attachment, GLenu ...@@ -1287,29 +1238,14 @@ void GL_APIENTRY FramebufferRenderbuffer(GLenum target, GLenum attachment, GLenu
Context *context = GetValidGlobalContext(); Context *context = GetValidGlobalContext();
if (context) if (context)
{ {
if (!ValidFramebufferTarget(target) || (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0)) if (!context->skipValidation() &&
!ValidateFramebufferRenderbuffer(context, target, attachment, renderbuffertarget,
renderbuffer))
{ {
context->recordError(Error(GL_INVALID_ENUM));
return; return;
} }
if (!ValidateFramebufferRenderbufferParameters(context, target, attachment, renderbuffertarget, renderbuffer)) context->framebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer);
{
return;
}
Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
ASSERT(framebuffer);
if (renderbuffer != 0)
{
Renderbuffer *renderbufferObject = context->getRenderbuffer(renderbuffer);
framebuffer->setAttachment(GL_RENDERBUFFER, attachment, gl::ImageIndex::MakeInvalid(), renderbufferObject);
}
else
{
framebuffer->resetAttachment(attachment);
}
} }
} }
...@@ -1321,36 +1257,13 @@ void GL_APIENTRY FramebufferTexture2D(GLenum target, GLenum attachment, GLenum t ...@@ -1321,36 +1257,13 @@ void GL_APIENTRY FramebufferTexture2D(GLenum target, GLenum attachment, GLenum t
Context *context = GetValidGlobalContext(); Context *context = GetValidGlobalContext();
if (context) if (context)
{ {
if (!ValidateFramebufferTexture2D(context, target, attachment, textarget, texture, level)) if (!context->skipValidation() &&
!ValidateFramebufferTexture2D(context, target, attachment, textarget, texture, level))
{ {
return; return;
} }
Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target); context->framebufferTexture2D(target, attachment, textarget, texture, level);
ASSERT(framebuffer);
if (texture != 0)
{
Texture *textureObj = context->getTexture(texture);
ImageIndex index = ImageIndex::MakeInvalid();
if (textarget == GL_TEXTURE_2D)
{
index = ImageIndex::Make2D(level);
}
else
{
ASSERT(IsCubeMapTextureTarget(textarget));
index = ImageIndex::MakeCube(textarget, level);
}
framebuffer->setAttachment(GL_TEXTURE, attachment, index, textureObj);
}
else
{
framebuffer->resetAttachment(attachment);
}
} }
} }
...@@ -3213,28 +3126,13 @@ void GL_APIENTRY ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, ...@@ -3213,28 +3126,13 @@ void GL_APIENTRY ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
Context *context = GetValidGlobalContext(); Context *context = GetValidGlobalContext();
if (context) if (context)
{ {
if (width < 0 || height < 0) if (!context->skipValidation() &&
!ValidateReadPixels(context, x, y, width, height, format, type, pixels))
{ {
context->recordError(Error(GL_INVALID_VALUE));
return; return;
} }
if (!ValidateReadPixelsParameters(context, x, y, width, height, context->readPixels(x, y, width, height, format, type, pixels);
format, type, NULL, pixels))
{
return;
}
Framebuffer *framebufferObject = context->getState().getReadFramebuffer();
ASSERT(framebufferObject);
Rectangle area(x, y, width, height);
Error error = framebufferObject->readPixels(context, area, format, type, pixels);
if (error.isError())
{
context->recordError(error);
return;
}
} }
} }
......
...@@ -480,28 +480,13 @@ void GL_APIENTRY ReadnPixelsEXT(GLint x, GLint y, GLsizei width, GLsizei height, ...@@ -480,28 +480,13 @@ void GL_APIENTRY ReadnPixelsEXT(GLint x, GLint y, GLsizei width, GLsizei height,
Context *context = GetValidGlobalContext(); Context *context = GetValidGlobalContext();
if (context) if (context)
{ {
if (width < 0 || height < 0 || bufSize < 0) if (!context->skipValidation() &&
{ !ValidateReadnPixelsEXT(context, x, y, width, height, format, type, bufSize, data))
context->recordError(Error(GL_INVALID_VALUE));
return;
}
if (!ValidateReadPixelsParameters(context, x, y, width, height,
format, type, &bufSize, data))
{ {
return; return;
} }
Framebuffer *framebufferObject = context->getState().getReadFramebuffer(); context->readPixels(x, y, width, height, format, type, data);
ASSERT(framebufferObject);
Rectangle area(x, y, width, height);
Error error = framebufferObject->readPixels(context, area, format, type, data);
if (error.isError())
{
context->recordError(error);
return;
}
} }
} }
...@@ -674,29 +659,15 @@ void GL_APIENTRY BlitFramebufferANGLE(GLint srcX0, GLint srcY0, GLint srcX1, GLi ...@@ -674,29 +659,15 @@ void GL_APIENTRY BlitFramebufferANGLE(GLint srcX0, GLint srcY0, GLint srcX1, GLi
Context *context = GetValidGlobalContext(); Context *context = GetValidGlobalContext();
if (context) if (context)
{ {
if (!ValidateBlitFramebufferParameters(context, srcX0, srcY0, srcX1, srcY1, if (!context->skipValidation() &&
dstX0, dstY0, dstX1, dstY1, mask, filter, !ValidateBlitFramebufferANGLE(context, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1,
true)) dstY1, mask, filter))
{ {
return; return;
} }
Framebuffer *readFramebuffer = context->getState().getReadFramebuffer(); context->blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask,
ASSERT(readFramebuffer); filter);
Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer();
ASSERT(drawFramebuffer);
Rectangle srcArea(srcX0, srcY0, srcX1 - srcX0, srcY1 - srcY0);
Rectangle dstArea(dstX0, dstY0, dstX1 - dstX0, dstY1 - dstY0);
Error error =
drawFramebuffer->blit(context, srcArea, dstArea, mask, filter, readFramebuffer);
if (error.isError())
{
context->recordError(error);
return;
}
} }
} }
...@@ -707,28 +678,13 @@ void GL_APIENTRY DiscardFramebufferEXT(GLenum target, GLsizei numAttachments, co ...@@ -707,28 +678,13 @@ void GL_APIENTRY DiscardFramebufferEXT(GLenum target, GLsizei numAttachments, co
Context *context = GetValidGlobalContext(); Context *context = GetValidGlobalContext();
if (context) if (context)
{ {
if (!context->getExtensions().discardFramebuffer) if (!context->skipValidation() &&
{ !ValidateDiscardFramebufferEXT(context, target, numAttachments, attachments))
context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled"));
return;
}
if (!ValidateDiscardFramebufferEXT(context, target, numAttachments, attachments))
{ {
return; return;
} }
Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target); context->discardFramebuffer(target, numAttachments, attachments);
ASSERT(framebuffer);
// The specification isn't clear what should be done when the framebuffer isn't complete.
// We leave it up to the framebuffer implementation to decide what to do.
Error error = framebuffer->discard(numAttachments, attachments);
if (error.isError())
{
context->recordError(error);
return;
}
} }
} }
...@@ -800,15 +756,12 @@ void GL_APIENTRY DrawBuffersEXT(GLsizei n, const GLenum *bufs) ...@@ -800,15 +756,12 @@ void GL_APIENTRY DrawBuffersEXT(GLsizei n, const GLenum *bufs)
Context *context = GetValidGlobalContext(); Context *context = GetValidGlobalContext();
if (context) if (context)
{ {
if (!ValidateDrawBuffers(context, n, bufs)) if (!context->skipValidation() && !ValidateDrawBuffersEXT(context, n, bufs))
{ {
return; return;
} }
Framebuffer *framebuffer = context->getState().getDrawFramebuffer(); context->drawBuffers(n, bufs);
ASSERT(framebuffer);
framebuffer->setDrawBuffers(n, bufs);
} }
} }
......
...@@ -35,13 +35,12 @@ void GL_APIENTRY ReadBuffer(GLenum mode) ...@@ -35,13 +35,12 @@ void GL_APIENTRY ReadBuffer(GLenum mode)
Context *context = GetValidGlobalContext(); Context *context = GetValidGlobalContext();
if (context) if (context)
{ {
if (!ValidateReadBuffer(context, mode)) if (!context->skipValidation() && !ValidateReadBuffer(context, mode))
{ {
return; return;
} }
Framebuffer *readFBO = context->getState().getReadFramebuffer(); context->readBuffer(mode);
readFBO->setReadBuffer(mode);
} }
} }
...@@ -171,29 +170,14 @@ void GL_APIENTRY CopyTexSubImage3D(GLenum target, GLint level, GLint xoffset, GL ...@@ -171,29 +170,14 @@ void GL_APIENTRY CopyTexSubImage3D(GLenum target, GLint level, GLint xoffset, GL
Context *context = GetValidGlobalContext(); Context *context = GetValidGlobalContext();
if (context) if (context)
{ {
if (context->getClientVersion() < 3) if (!context->skipValidation() &&
{ !ValidateCopyTexSubImage3D(context, target, level, xoffset, yoffset, zoffset, x, y,
context->recordError(Error(GL_INVALID_OPERATION)); width, height))
return;
}
if (!ValidateES3CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset, yoffset, zoffset,
x, y, width, height, 0))
{ {
return; return;
} }
Offset destOffset(xoffset, yoffset, zoffset); context->copyTexSubImage3D(target, level, xoffset, yoffset, zoffset, x, y, width, height);
Rectangle sourceArea(x, y, width, height);
const Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Texture *texture = context->getTargetTexture(target);
Error error = texture->copySubImage(target, level, destOffset, sourceArea, framebuffer);
if (error.isError())
{
context->recordError(error);
return;
}
} }
} }
...@@ -207,8 +191,8 @@ void GL_APIENTRY CompressedTexImage3D(GLenum target, GLint level, GLenum interna ...@@ -207,8 +191,8 @@ void GL_APIENTRY CompressedTexImage3D(GLenum target, GLint level, GLenum interna
Context *context = GetValidGlobalContext(); Context *context = GetValidGlobalContext();
if (context) if (context)
{ {
if (!gl::ValidateCompressedTexImage3D(context, target, level, internalformat, width, height, if (!ValidateCompressedTexImage3D(context, target, level, internalformat, width, height,
depth, border, imageSize, data)) depth, border, imageSize, data))
{ {
return; return;
} }
...@@ -537,13 +521,12 @@ void GL_APIENTRY DrawBuffers(GLsizei n, const GLenum* bufs) ...@@ -537,13 +521,12 @@ void GL_APIENTRY DrawBuffers(GLsizei n, const GLenum* bufs)
Context *context = GetValidGlobalContext(); Context *context = GetValidGlobalContext();
if (context) if (context)
{ {
if (context->getClientVersion() < 3) if (!context->skipValidation() && !ValidateDrawBuffers(context, n, bufs))
{ {
context->recordError(Error(GL_INVALID_OPERATION));
return; return;
} }
DrawBuffersEXT(n, bufs); context->drawBuffers(n, bufs);
} }
} }
...@@ -664,35 +647,15 @@ void GL_APIENTRY BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint sr ...@@ -664,35 +647,15 @@ void GL_APIENTRY BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint sr
Context *context = GetValidGlobalContext(); Context *context = GetValidGlobalContext();
if (context) if (context)
{ {
if (context->getClientVersion() < 3) if (!context->skipValidation() &&
!ValidateBlitFramebuffer(context, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1,
dstY1, mask, filter))
{ {
context->recordError(Error(GL_INVALID_OPERATION));
return; return;
} }
if (!ValidateBlitFramebufferParameters(context, srcX0, srcY0, srcX1, srcY1, context->blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask,
dstX0, dstY0, dstX1, dstY1, mask, filter, filter);
false))
{
return;
}
Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
ASSERT(readFramebuffer);
Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer();
ASSERT(drawFramebuffer);
Rectangle srcArea(srcX0, srcY0, srcX1 - srcX0, srcY1 - srcY0);
Rectangle dstArea(dstX0, dstY0, dstX1 - dstX0, dstY1 - dstY0);
Error error =
drawFramebuffer->blit(context, srcArea, dstArea, mask, filter, readFramebuffer);
if (error.isError())
{
context->recordError(error);
return;
}
} }
} }
...@@ -728,37 +691,13 @@ void GL_APIENTRY FramebufferTextureLayer(GLenum target, GLenum attachment, GLuin ...@@ -728,37 +691,13 @@ void GL_APIENTRY FramebufferTextureLayer(GLenum target, GLenum attachment, GLuin
Context *context = GetValidGlobalContext(); Context *context = GetValidGlobalContext();
if (context) if (context)
{ {
if (!ValidateFramebufferTextureLayer(context, target, attachment, texture, if (!context->skipValidation() &&
level, layer)) !ValidateFramebufferTextureLayer(context, target, attachment, texture, level, layer))
{ {
return; return;
} }
Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target); context->framebufferTextureLayer(target, attachment, texture, level, layer);
ASSERT(framebuffer);
if (texture != 0)
{
Texture *textureObject = context->getTexture(texture);
ImageIndex index = ImageIndex::MakeInvalid();
if (textureObject->getTarget() == GL_TEXTURE_3D)
{
index = ImageIndex::Make3D(level, layer);
}
else
{
ASSERT(textureObject->getTarget() == GL_TEXTURE_2D_ARRAY);
index = ImageIndex::Make2DArray(level, layer);
}
framebuffer->setAttachment(GL_TEXTURE, attachment, index, textureObject);
}
else
{
framebuffer->resetAttachment(attachment);
}
} }
} }
...@@ -1674,43 +1613,13 @@ void GL_APIENTRY ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* val ...@@ -1674,43 +1613,13 @@ void GL_APIENTRY ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* val
Context *context = GetValidGlobalContext(); Context *context = GetValidGlobalContext();
if (context) if (context)
{ {
if (!ValidateClearBuffer(context)) if (!context->skipValidation() &&
!ValidateClearBufferiv(context, buffer, drawbuffer, value))
{ {
return; return;
} }
switch (buffer) context->clearBufferiv(buffer, drawbuffer, value);
{
case GL_COLOR:
if (drawbuffer < 0 || static_cast<GLuint>(drawbuffer) >= context->getCaps().maxDrawBuffers)
{
context->recordError(Error(GL_INVALID_VALUE));
return;
}
break;
case GL_STENCIL:
if (drawbuffer != 0)
{
context->recordError(Error(GL_INVALID_VALUE));
return;
}
break;
default:
context->recordError(Error(GL_INVALID_ENUM));
return;
}
Framebuffer *framebufferObject = context->getState().getDrawFramebuffer();
ASSERT(framebufferObject);
Error error = framebufferObject->clearBufferiv(context, buffer, drawbuffer, value);
if (error.isError())
{
context->recordError(error);
return;
}
} }
} }
...@@ -1722,35 +1631,13 @@ void GL_APIENTRY ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* v ...@@ -1722,35 +1631,13 @@ void GL_APIENTRY ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* v
Context *context = GetValidGlobalContext(); Context *context = GetValidGlobalContext();
if (context) if (context)
{ {
if (!ValidateClearBuffer(context)) if (!context->skipValidation() &&
!ValidateClearBufferuiv(context, buffer, drawbuffer, value))
{ {
return; return;
} }
switch (buffer) context->clearBufferuiv(buffer, drawbuffer, value);
{
case GL_COLOR:
if (drawbuffer < 0 || static_cast<GLuint>(drawbuffer) >= context->getCaps().maxDrawBuffers)
{
context->recordError(Error(GL_INVALID_VALUE));
return;
}
break;
default:
context->recordError(Error(GL_INVALID_ENUM));
return;
}
Framebuffer *framebufferObject = context->getState().getDrawFramebuffer();
ASSERT(framebufferObject);
Error error = framebufferObject->clearBufferuiv(context, buffer, drawbuffer, value);
if (error.isError())
{
context->recordError(error);
return;
}
} }
} }
...@@ -1762,43 +1649,13 @@ void GL_APIENTRY ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* v ...@@ -1762,43 +1649,13 @@ void GL_APIENTRY ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* v
Context *context = GetValidGlobalContext(); Context *context = GetValidGlobalContext();
if (context) if (context)
{ {
if (!ValidateClearBuffer(context)) if (!context->skipValidation() &&
!ValidateClearBufferfv(context, buffer, drawbuffer, value))
{ {
return; return;
} }
switch (buffer) context->clearBufferfv(buffer, drawbuffer, value);
{
case GL_COLOR:
if (drawbuffer < 0 || static_cast<GLuint>(drawbuffer) >= context->getCaps().maxDrawBuffers)
{
context->recordError(Error(GL_INVALID_VALUE));
return;
}
break;
case GL_DEPTH:
if (drawbuffer != 0)
{
context->recordError(Error(GL_INVALID_VALUE));
return;
}
break;
default:
context->recordError(Error(GL_INVALID_ENUM));
return;
}
Framebuffer *framebufferObject = context->getState().getDrawFramebuffer();
ASSERT(framebufferObject);
Error error = framebufferObject->clearBufferfv(context, buffer, drawbuffer, value);
if (error.isError())
{
context->recordError(error);
return;
}
} }
} }
...@@ -1810,41 +1667,13 @@ void GL_APIENTRY ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, G ...@@ -1810,41 +1667,13 @@ void GL_APIENTRY ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, G
Context *context = GetValidGlobalContext(); Context *context = GetValidGlobalContext();
if (context) if (context)
{ {
if (!ValidateClearBuffer(context)) if (!context->skipValidation() &&
{ !ValidateClearBufferfi(context, buffer, drawbuffer, depth, stencil))
return;
}
switch (buffer)
{ {
case GL_DEPTH_STENCIL:
if (drawbuffer != 0)
{
context->recordError(Error(GL_INVALID_VALUE));
return;
}
break;
default:
context->recordError(Error(GL_INVALID_ENUM));
return; return;
} }
Framebuffer *framebufferObject = context->getState().getDrawFramebuffer(); context->clearBufferfi(buffer, drawbuffer, depth, stencil);
ASSERT(framebufferObject);
// If a buffer is not present, the clear has no effect
if (framebufferObject->getDepthbuffer() == nullptr && framebufferObject->getStencilbuffer() == nullptr)
{
return;
}
Error error = framebufferObject->clearBufferfi(context, buffer, drawbuffer, depth, stencil);
if (error.isError())
{
context->recordError(error);
return;
}
} }
} }
...@@ -3150,23 +2979,13 @@ void GL_APIENTRY InvalidateFramebuffer(GLenum target, GLsizei numAttachments, co ...@@ -3150,23 +2979,13 @@ void GL_APIENTRY InvalidateFramebuffer(GLenum target, GLsizei numAttachments, co
Context *context = GetValidGlobalContext(); Context *context = GetValidGlobalContext();
if (context) if (context)
{ {
if (!ValidateInvalidateFramebuffer(context, target, numAttachments, attachments)) if (!context->skipValidation() &&
!ValidateInvalidateFramebuffer(context, target, numAttachments, attachments))
{ {
return; return;
} }
Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target); context->invalidateFramebuffer(target, numAttachments, attachments);
ASSERT(framebuffer);
if (framebuffer->checkStatus(context->getData()) == GL_FRAMEBUFFER_COMPLETE)
{
Error error = framebuffer->invalidate(numAttachments, attachments);
if (error.isError())
{
context->recordError(error);
return;
}
}
} }
} }
...@@ -3179,24 +2998,13 @@ void GL_APIENTRY InvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, ...@@ -3179,24 +2998,13 @@ void GL_APIENTRY InvalidateSubFramebuffer(GLenum target, GLsizei numAttachments,
Context *context = GetValidGlobalContext(); Context *context = GetValidGlobalContext();
if (context) if (context)
{ {
if (!ValidateInvalidateFramebuffer(context, target, numAttachments, attachments)) if (!context->skipValidation() &&
!ValidateInvalidateFramebuffer(context, target, numAttachments, attachments))
{ {
return; return;
} }
Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target); context->invalidateSubFramebuffer(target, numAttachments, attachments, x, y, width, height);
ASSERT(framebuffer);
if (framebuffer->checkStatus(context->getData()) == GL_FRAMEBUFFER_COMPLETE)
{
Rectangle area(x, y, width, height);
Error error = framebuffer->invalidateSub(numAttachments, attachments, area);
if (error.isError())
{
context->recordError(error);
return;
}
}
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment