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
Texture *Context::getTargetTexture(GLenum target) const
{
ASSERT(ValidTextureTarget(this, target));
return getSamplerTexture(mState.getActiveSampler(), target);
return mState.getTargetTexture(target);
}
Texture *Context::getSamplerTexture(unsigned int sampler, GLenum type) const
......@@ -1936,4 +1935,346 @@ void Context::syncRendererState(const State::DirtyBits &bitMask)
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
bool getQueryParameterInfo(GLenum pname, 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 drawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount);
......@@ -197,6 +203,83 @@ class Context final : public ValidationContext
const GLvoid *indices,
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 finish();
......
......@@ -590,81 +590,67 @@ Error Framebuffer::invalidateSub(size_t count, const GLenum *attachments, const
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);
}
// Sync the clear state
context->syncRendererState(context->getState().clearStateBitMask());
return mImpl->clear(context->getData(), mask);
return mImpl->clear(data, mask);
}
Error Framebuffer::clearBufferfv(Context *context,
Error Framebuffer::clearBufferfv(const gl::Data &data,
GLenum buffer,
GLint drawbuffer,
const GLfloat *values)
{
if (context->getState().isRasterizerDiscardEnabled())
if (data.state->isRasterizerDiscardEnabled())
{
return gl::Error(GL_NO_ERROR);
}
// Sync the clear state
context->syncRendererState(context->getState().clearStateBitMask());
return mImpl->clearBufferfv(context->getData(), buffer, drawbuffer, values);
return mImpl->clearBufferfv(data, buffer, drawbuffer, values);
}
Error Framebuffer::clearBufferuiv(Context *context,
Error Framebuffer::clearBufferuiv(const gl::Data &data,
GLenum buffer,
GLint drawbuffer,
const GLuint *values)
{
if (context->getState().isRasterizerDiscardEnabled())
if (data.state->isRasterizerDiscardEnabled())
{
return gl::Error(GL_NO_ERROR);
}
// Sync the clear state
context->syncRendererState(context->getState().clearStateBitMask());
return mImpl->clearBufferuiv(context->getData(), buffer, drawbuffer, values);
return mImpl->clearBufferuiv(data, buffer, drawbuffer, values);
}
Error Framebuffer::clearBufferiv(Context *context,
Error Framebuffer::clearBufferiv(const gl::Data &data,
GLenum buffer,
GLint drawbuffer,
const GLint *values)
{
if (context->getState().isRasterizerDiscardEnabled())
if (data.state->isRasterizerDiscardEnabled())
{
return gl::Error(GL_NO_ERROR);
}
// Sync the clear state
context->syncRendererState(context->getState().clearStateBitMask());
return mImpl->clearBufferiv(context->getData(), buffer, drawbuffer, values);
return mImpl->clearBufferiv(data, buffer, drawbuffer, values);
}
Error Framebuffer::clearBufferfi(Context *context,
Error Framebuffer::clearBufferfi(const gl::Data &data,
GLenum buffer,
GLint drawbuffer,
GLfloat depth,
GLint stencil)
{
if (context->getState().isRasterizerDiscardEnabled())
if (data.state->isRasterizerDiscardEnabled())
{
return gl::Error(GL_NO_ERROR);
}
// Sync the clear state
context->syncRendererState(context->getState().clearStateBitMask());
return mImpl->clearBufferfi(context->getData(), buffer, drawbuffer, depth, stencil);
return mImpl->clearBufferfi(data, buffer, drawbuffer, depth, stencil);
}
GLenum Framebuffer::getImplementationColorReadFormat() const
......@@ -677,17 +663,12 @@ GLenum Framebuffer::getImplementationColorReadType() const
return mImpl->getImplementationColorReadType();
}
Error Framebuffer::readPixels(Context *context,
const gl::Rectangle &area,
Error Framebuffer::readPixels(const State &state,
const Rectangle &area,
GLenum format,
GLenum type,
GLvoid *pixels) const
{
const State &state = context->getState();
// Sync pack state
context->syncRendererState(state.packStateBitMask());
Error error = mImpl->readPixels(state, area, format, type, pixels);
if (error.isError())
{
......@@ -703,17 +684,13 @@ Error Framebuffer::readPixels(Context *context,
return Error(GL_NO_ERROR);
}
Error Framebuffer::blit(Context *context,
const gl::Rectangle &sourceArea,
const gl::Rectangle &destArea,
Error Framebuffer::blit(const State &state,
const Rectangle &sourceArea,
const Rectangle &destArea,
GLbitfield mask,
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);
}
......
......@@ -137,11 +137,17 @@ class Framebuffer final : public LabeledObject
Error invalidate(size_t count, const GLenum *attachments);
Error invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area);
Error clear(Context *context, GLbitfield mask);
Error clearBufferfv(Context *context, GLenum buffer, GLint drawbuffer, const GLfloat *values);
Error clearBufferuiv(Context *context, GLenum buffer, GLint drawbuffer, const GLuint *values);
Error clearBufferiv(Context *context, GLenum buffer, GLint drawbuffer, const GLint *values);
Error clearBufferfi(Context *context,
Error clear(const gl::Data &data, GLbitfield mask);
Error clearBufferfv(const gl::Data &data,
GLenum buffer,
GLint drawbuffer,
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,
GLint drawbuffer,
GLfloat depth,
......@@ -149,18 +155,18 @@ class Framebuffer final : public LabeledObject
GLenum getImplementationColorReadFormat() const;
GLenum getImplementationColorReadType() const;
Error readPixels(Context *context,
Error readPixels(const gl::State &state,
const gl::Rectangle &area,
GLenum format,
GLenum type,
GLvoid *pixels) const;
Error blit(Context *context,
const gl::Rectangle &sourceArea,
const gl::Rectangle &destArea,
Error blit(const State &state,
const Rectangle &sourceArea,
const Rectangle &destArea,
GLbitfield mask,
GLenum filter,
const gl::Framebuffer *sourceFramebuffer);
const Framebuffer *sourceFramebuffer);
protected:
void detachResourceById(GLenum resourceType, GLuint resourceId);
......
......@@ -676,6 +676,11 @@ void State::setSamplerTexture(GLenum type, Texture *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
{
const auto it = mSamplerTextures.find(type);
......
......@@ -149,6 +149,7 @@ class State : angle::NonCopyable
void setActiveSampler(unsigned int active);
unsigned int getActiveSampler() const;
void setSamplerTexture(GLenum type, Texture *texture);
Texture *getTargetTexture(GLenum target) const;
Texture *getSamplerTexture(unsigned int sampler, GLenum type) const;
GLuint getSamplerTextureId(unsigned int sampler, GLenum type) const;
void detachTexture(const TextureMap &zeroTextures, GLuint texture);
......
......@@ -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
// GL_TEXTURE_CUBE_MAP is not.
// Note: duplicate of IsInternalTextureTarget
bool ValidTexture2DDestinationTarget(const Context *context, GLenum target)
bool ValidTexture2DDestinationTarget(const ValidationContext *context, GLenum target)
{
switch (target)
{
......@@ -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;
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_POSITIVE_X:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: maxDimension = context->getCaps().maxCubeMapTextureSize; break;
case GL_TEXTURE_3D: maxDimension = context->getCaps().max3DTextureSize; break;
case GL_TEXTURE_2D_ARRAY: maxDimension = context->getCaps().max2DTextureSize; break;
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
maxDimension = caps.maxCubeMapTextureSize;
break;
case GL_TEXTURE_3D:
maxDimension = caps.max3DTextureSize;
break;
case GL_TEXTURE_2D_ARRAY:
maxDimension = caps.max2DTextureSize;
break;
default: UNREACHABLE();
}
......@@ -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);
if (!formatInfo.compressed)
......@@ -545,45 +557,23 @@ bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum targ
return true;
}
static bool IsPartialBlit(gl::Context *context, const gl::FramebufferAttachment *readBuffer, const gl::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;
}
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)
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)
{
switch (filter)
{
case GL_NEAREST:
break;
case GL_LINEAR:
if (fromAngleExtension)
{
context->recordError(Error(GL_INVALID_ENUM));
return false;
}
break;
default:
context->recordError(Error(GL_INVALID_ENUM));
......@@ -603,13 +593,6 @@ bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint
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
// color buffer, leaving only nearest being unfiltered from above
if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
......@@ -620,11 +603,6 @@ bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint
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));
return false;
}
......@@ -737,54 +715,6 @@ bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint
context->recordError(Error(GL_INVALID_OPERATION));
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
context->recordError(Error(GL_INVALID_OPERATION));
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)
}
}
bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsizei width, GLsizei height,
GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels)
bool ValidateReadPixels(Context *context,
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);
if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
......@@ -1096,6 +1021,25 @@ bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsize
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);
const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
......@@ -1103,17 +1047,14 @@ bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsize
sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment(),
context->getState().getPackRowLength());
// sized query sanity check
if (bufSize)
int requiredSize = outputPitch * height;
if (requiredSize > bufSize)
{
int requiredSize = outputPitch * height;
if (requiredSize > *bufSize)
{
context->recordError(Error(GL_INVALID_OPERATION));
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)
......@@ -1359,9 +1300,20 @@ bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType,
return true;
}
bool ValidateCopyTexImageParametersBase(gl::Context *context, GLenum target, GLint level, GLenum internalformat, bool isSubImage,
GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height,
GLint border, GLenum *textureFormatOut)
bool ValidateCopyTexImageParametersBase(ValidationContext *context,
GLenum target,
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))
......@@ -1394,14 +1346,15 @@ bool ValidateCopyTexImageParametersBase(gl::Context *context, GLenum target, GLi
return false;
}
gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
const gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
{
context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
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));
return false;
......@@ -1438,7 +1391,8 @@ bool ValidateCopyTexImageParametersBase(gl::Context *context, GLenum target, GLi
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)
{
context->recordError(Error(GL_INVALID_OPERATION));
......@@ -2300,4 +2254,128 @@ bool ValidateGetProgramBinaryBase(Context *context,
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;
namespace gl
{
class Context;
class Program;
class Shader;
......@@ -30,11 +29,11 @@ class ValidationContext;
bool ValidCap(const Context *context, GLenum cap);
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 ValidBufferTarget(const Context *context, GLenum target);
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,
GLenum target,
GLint level,
......@@ -42,7 +41,10 @@ bool ValidImageSizeParameters(const Context *context,
GLsizei height,
GLsizei depth,
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);
// Returns valid program if id is a valid program name
......@@ -64,9 +66,17 @@ bool ValidateRenderbufferStorageParametersANGLE(Context *context, GLenum target,
bool ValidateFramebufferRenderbufferParameters(Context *context, GLenum target, GLenum attachment,
GLenum renderbuffertarget, GLuint renderbuffer);
bool ValidateBlitFramebufferParameters(Context *context, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
GLenum filter, bool fromAngleExtension);
bool ValidateBlitFramebufferParameters(Context *context,
GLint srcX0,
GLint srcY0,
GLint srcX1,
GLint srcY1,
GLint dstX0,
GLint dstY0,
GLint dstX1,
GLint dstY1,
GLbitfield mask,
GLenum filter);
bool ValidateGetVertexAttribParameters(Context *context, GLenum pname);
......@@ -74,8 +84,23 @@ bool ValidateTexParamParameters(Context *context, GLenum pname, GLint param);
bool ValidateSamplerObjectParameter(Context *context, GLenum pname);
bool ValidateReadPixelsParameters(Context *context, GLint x, GLint y, GLsizei width, GLsizei height,
GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels);
bool ValidateReadPixels(Context *context,
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 ValidateEndQuery(Context *context, GLenum target);
......@@ -86,9 +111,20 @@ bool ValidateUniformMatrix(Context *context, GLenum matrixType, GLint location,
bool ValidateStateQuery(Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams);
bool ValidateCopyTexImageParametersBase(Context *context, GLenum target, 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 ValidateCopyTexImageParametersBase(ValidationContext *context,
GLenum target,
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 ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount);
......@@ -121,6 +157,11 @@ bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum atta
GLuint texture, GLint level);
bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
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 ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params);
......@@ -159,8 +200,28 @@ bool ValidateGetProgramBinaryBase(Context *context,
GLenum *binaryFormat,
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.
extern const char *g_ExceedsMaxElementErrorMessage;
}
} // namespace gl
#endif // LIBANGLE_VALIDATION_ES_H_
......@@ -21,6 +21,42 @@
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,
GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
GLint border, GLenum format, GLenum type, const GLvoid *pixels)
......@@ -407,10 +443,17 @@ bool ValidateES2TexImageParameters(Context *context, GLenum target, GLint level,
return true;
}
bool ValidateES2CopyTexImageParameters(Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage,
GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height,
bool ValidateES2CopyTexImageParameters(ValidationContext *context,
GLenum target,
GLint level,
GLenum internalformat,
bool isSubImage,
GLint xoffset,
GLint yoffset,
GLint x,
GLint y,
GLsizei width,
GLsizei height,
GLint border)
{
GLenum textureInternalFormat = GL_NONE;
......@@ -421,7 +464,7 @@ bool ValidateES2CopyTexImageParameters(Context* context, GLenum target, GLint le
return false;
}
gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
const gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
GLenum colorbufferFormat = framebuffer->getReadColorbuffer()->getInternalFormat();
const auto &internalFormatInfo = gl::GetInternalFormatInfo(textureInternalFormat);
GLenum textureFormat = internalFormatInfo.format;
......@@ -914,6 +957,12 @@ bool ValidES2ReadFormatType(Context *context, GLenum format, GLenum type)
bool ValidateDiscardFramebufferEXT(Context *context, GLenum target, GLsizei numAttachments,
const GLenum *attachments)
{
if (!context->getExtensions().discardFramebuffer)
{
context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled"));
return false;
}
bool defaultFramebuffer = false;
switch (target)
......@@ -929,71 +978,6 @@ bool ValidateDiscardFramebufferEXT(Context *context, GLenum target, GLsizei numA
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)
{
if (!context->getExtensions().vertexArrayObject)
......@@ -1559,4 +1543,164 @@ bool ValidateGetPointervKHR(Context *context, GLenum pname, void **params)
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 @@
namespace gl
{
class Context;
class ValidationContext;
bool ValidateES2TexImageParameters(Context *context, GLenum target, GLint level, GLenum internalformat, bool isCompressed, bool isSubImage,
GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
GLint border, GLenum format, GLenum type, const GLvoid *pixels);
bool ValidateES2CopyTexImageParameters(Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage,
GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height,
bool ValidateES2CopyTexImageParameters(ValidationContext *context,
GLenum target,
GLint level,
GLenum internalformat,
bool isSubImage,
GLint xoffset,
GLint yoffset,
GLint x,
GLint y,
GLsizei width,
GLsizei height,
GLint border);
bool ValidateES2TexStorageParameters(Context *context, GLenum target, GLsizei levels, GLenum internalformat,
......@@ -33,7 +42,7 @@ bool ValidES2ReadFormatType(Context *context, GLenum format, GLenum type);
bool ValidateDiscardFramebufferEXT(Context *context, GLenum target, GLsizei numAttachments,
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 ValidateDeleteVertexArraysOES(Context *context, GLsizei n);
......@@ -106,6 +115,20 @@ bool ValidateGetObjectPtrLabelKHR(Context *context,
GLsizei *length,
GLchar *label);
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_
......@@ -786,9 +786,19 @@ static bool IsValidES3CopyTexImageCombination(GLenum textureInternalFormat, GLen
return false;
}
bool ValidateES3CopyTexImageParameters(Context *context, GLenum target, GLint level, GLenum internalformat,
bool isSubImage, GLint xoffset, GLint yoffset, GLint zoffset,
GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
bool ValidateES3CopyTexImageParameters(ValidationContext *context,
GLenum target,
GLint level,
GLenum internalformat,
bool isSubImage,
GLint xoffset,
GLint yoffset,
GLint zoffset,
GLint x,
GLint y,
GLsizei width,
GLsizei height,
GLint border)
{
GLenum textureInternalFormat;
if (!ValidateCopyTexImageParametersBase(context, target, level, internalformat, isSubImage,
......@@ -798,7 +808,9 @@ bool ValidateES3CopyTexImageParameters(Context *context, GLenum target, GLint le
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)
{
......@@ -806,8 +818,7 @@ bool ValidateES3CopyTexImageParameters(Context *context, GLenum target, GLint le
return false;
}
if (context->getState().getReadFramebuffer()->id() != 0 &&
framebuffer->getSamples(context->getData()) != 0)
if (readFramebufferID != 0 && framebuffer->getSamples(context->getData()) != 0)
{
context->recordError(Error(GL_INVALID_OPERATION));
return false;
......@@ -819,7 +830,7 @@ bool ValidateES3CopyTexImageParameters(Context *context, GLenum target, GLint le
if (isSubImage)
{
if (!IsValidES3CopyTexImageCombination(textureInternalFormat, colorbufferInternalFormat,
context->getState().getReadFramebuffer()->id()))
readFramebufferID))
{
context->recordError(Error(GL_INVALID_OPERATION));
return false;
......@@ -828,7 +839,7 @@ bool ValidateES3CopyTexImageParameters(Context *context, GLenum target, GLint le
else
{
if (!gl::IsValidES3CopyTexImageCombination(internalformat, colorbufferInternalFormat,
context->getState().getReadFramebuffer()->id()))
readFramebufferID))
{
context->recordError(Error(GL_INVALID_OPERATION));
return false;
......@@ -1157,7 +1168,7 @@ bool ValidateInvalidateFramebuffer(Context *context, GLenum target, GLsizei numA
return ValidateDiscardFramebufferBase(context, target, numAttachments, attachments, defaultFramebuffer);
}
bool ValidateClearBuffer(Context *context)
bool ValidateClearBuffer(ValidationContext *context)
{
if (context->getClientVersion() < 3)
{
......@@ -1381,4 +1392,171 @@ bool ValidateProgramParameter(Context *context, GLuint program, GLenum pname, GL
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 @@
namespace gl
{
class Context;
class ValidationContext;
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 border, GLenum format, GLenum type, const GLvoid *pixels);
bool ValidateES3CopyTexImageParameters(Context *context, GLenum target, GLint level, GLenum internalformat,
bool isSubImage, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y,
GLsizei width, GLsizei height, GLint border);
bool ValidateES3CopyTexImageParameters(ValidationContext *context,
GLenum target,
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,
GLsizei width, GLsizei height, GLsizei depth);
......@@ -38,7 +48,7 @@ bool ValidateES3RenderbufferStorageParameters(Context *context, GLenum target, G
bool ValidateInvalidateFramebuffer(Context *context, GLenum target, GLsizei numAttachments,
const GLenum *attachments);
bool ValidateClearBuffer(Context *context);
bool ValidateClearBuffer(ValidationContext *context);
bool ValidateGetUniformuiv(Context *context, GLuint program, GLint location, GLuint* params);
......@@ -72,6 +82,46 @@ bool ValidateGetProgramBinary(Context *context,
GLenum *binaryFormat,
void *binary);
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_
......@@ -593,27 +593,12 @@ void GL_APIENTRY Clear(GLbitfield mask)
Context *context = GetValidGlobalContext();
if (context)
{
Framebuffer *framebufferObject = context->getState().getDrawFramebuffer();
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)
if (!context->skipValidation() && !ValidateClear(context, mask))
{
context->recordError(Error(GL_INVALID_VALUE));
return;
}
Error error = framebufferObject->clear(context, mask);
if (error.isError())
{
context->recordError(error);
return;
}
context->clear(mask);
}
}
......@@ -777,30 +762,13 @@ void GL_APIENTRY CopyTexImage2D(GLenum target, GLint level, GLenum internalforma
Context *context = GetValidGlobalContext();
if (context)
{
if (context->getClientVersion() < 3 &&
!ValidateES2CopyTexImageParameters(context, target, level, internalformat, false,
0, 0, x, y, width, height, 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())
if (!context->skipValidation() &&
!ValidateCopyTexImage2D(context, target, level, internalformat, x, y, width, height,
border))
{
context->recordError(error);
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
Context *context = GetValidGlobalContext();
if (context)
{
if (context->getClientVersion() < 3 &&
!ValidateES2CopyTexImageParameters(context, target, level, GL_NONE, true,
xoffset, yoffset, x, y, width, height, 0))
{
return;
}
if (context->getClientVersion() >= 3 &&
!ValidateES3CopyTexImageParameters(context, target, level, GL_NONE, true,
xoffset, yoffset, 0, x, y, width, height, 0))
if (!context->skipValidation() &&
!ValidateCopyTexSubImage2D(context, target, level, xoffset, yoffset, x, y, width,
height))
{
return;
}
Offset destOffset(xoffset, yoffset, 0);
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;
}
context->copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
}
}
......@@ -1287,29 +1238,14 @@ void GL_APIENTRY FramebufferRenderbuffer(GLenum target, GLenum attachment, GLenu
Context *context = GetValidGlobalContext();
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;
}
if (!ValidateFramebufferRenderbufferParameters(context, 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);
}
context->framebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer);
}
}
......@@ -1321,36 +1257,13 @@ void GL_APIENTRY FramebufferTexture2D(GLenum target, GLenum attachment, GLenum t
Context *context = GetValidGlobalContext();
if (context)
{
if (!ValidateFramebufferTexture2D(context, target, attachment, textarget, texture, level))
if (!context->skipValidation() &&
!ValidateFramebufferTexture2D(context, target, attachment, textarget, texture, level))
{
return;
}
Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
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);
}
context->framebufferTexture2D(target, attachment, textarget, texture, level);
}
}
......@@ -3213,28 +3126,13 @@ void GL_APIENTRY ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
Context *context = GetValidGlobalContext();
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;
}
if (!ValidateReadPixelsParameters(context, x, y, width, height,
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;
}
context->readPixels(x, y, width, height, format, type, pixels);
}
}
......
......@@ -480,28 +480,13 @@ void GL_APIENTRY ReadnPixelsEXT(GLint x, GLint y, GLsizei width, GLsizei height,
Context *context = GetValidGlobalContext();
if (context)
{
if (width < 0 || height < 0 || bufSize < 0)
{
context->recordError(Error(GL_INVALID_VALUE));
return;
}
if (!ValidateReadPixelsParameters(context, x, y, width, height,
format, type, &bufSize, data))
if (!context->skipValidation() &&
!ValidateReadnPixelsEXT(context, x, y, width, height, format, type, bufSize, data))
{
return;
}
Framebuffer *framebufferObject = context->getState().getReadFramebuffer();
ASSERT(framebufferObject);
Rectangle area(x, y, width, height);
Error error = framebufferObject->readPixels(context, area, format, type, data);
if (error.isError())
{
context->recordError(error);
return;
}
context->readPixels(x, y, width, height, format, type, data);
}
}
......@@ -674,29 +659,15 @@ void GL_APIENTRY BlitFramebufferANGLE(GLint srcX0, GLint srcY0, GLint srcX1, GLi
Context *context = GetValidGlobalContext();
if (context)
{
if (!ValidateBlitFramebufferParameters(context, srcX0, srcY0, srcX1, srcY1,
dstX0, dstY0, dstX1, dstY1, mask, filter,
true))
if (!context->skipValidation() &&
!ValidateBlitFramebufferANGLE(context, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1,
dstY1, mask, filter))
{
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;
}
context->blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask,
filter);
}
}
......@@ -707,28 +678,13 @@ void GL_APIENTRY DiscardFramebufferEXT(GLenum target, GLsizei numAttachments, co
Context *context = GetValidGlobalContext();
if (context)
{
if (!context->getExtensions().discardFramebuffer)
{
context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled"));
return;
}
if (!ValidateDiscardFramebufferEXT(context, target, numAttachments, attachments))
if (!context->skipValidation() &&
!ValidateDiscardFramebufferEXT(context, target, numAttachments, attachments))
{
return;
}
Framebuffer *framebuffer = context->getState().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())
{
context->recordError(error);
return;
}
context->discardFramebuffer(target, numAttachments, attachments);
}
}
......@@ -800,15 +756,12 @@ void GL_APIENTRY DrawBuffersEXT(GLsizei n, const GLenum *bufs)
Context *context = GetValidGlobalContext();
if (context)
{
if (!ValidateDrawBuffers(context, n, bufs))
if (!context->skipValidation() && !ValidateDrawBuffersEXT(context, n, bufs))
{
return;
}
Framebuffer *framebuffer = context->getState().getDrawFramebuffer();
ASSERT(framebuffer);
framebuffer->setDrawBuffers(n, bufs);
context->drawBuffers(n, bufs);
}
}
......
......@@ -35,13 +35,12 @@ void GL_APIENTRY ReadBuffer(GLenum mode)
Context *context = GetValidGlobalContext();
if (context)
{
if (!ValidateReadBuffer(context, mode))
if (!context->skipValidation() && !ValidateReadBuffer(context, mode))
{
return;
}
Framebuffer *readFBO = context->getState().getReadFramebuffer();
readFBO->setReadBuffer(mode);
context->readBuffer(mode);
}
}
......@@ -171,29 +170,14 @@ void GL_APIENTRY CopyTexSubImage3D(GLenum target, GLint level, GLint xoffset, GL
Context *context = GetValidGlobalContext();
if (context)
{
if (context->getClientVersion() < 3)
{
context->recordError(Error(GL_INVALID_OPERATION));
return;
}
if (!ValidateES3CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset, yoffset, zoffset,
x, y, width, height, 0))
if (!context->skipValidation() &&
!ValidateCopyTexSubImage3D(context, target, level, xoffset, yoffset, zoffset, x, y,
width, height))
{
return;
}
Offset destOffset(xoffset, yoffset, zoffset);
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;
}
context->copyTexSubImage3D(target, level, xoffset, yoffset, zoffset, x, y, width, height);
}
}
......@@ -207,8 +191,8 @@ void GL_APIENTRY CompressedTexImage3D(GLenum target, GLint level, GLenum interna
Context *context = GetValidGlobalContext();
if (context)
{
if (!gl::ValidateCompressedTexImage3D(context, target, level, internalformat, width, height,
depth, border, imageSize, data))
if (!ValidateCompressedTexImage3D(context, target, level, internalformat, width, height,
depth, border, imageSize, data))
{
return;
}
......@@ -537,13 +521,12 @@ void GL_APIENTRY DrawBuffers(GLsizei n, const GLenum* bufs)
Context *context = GetValidGlobalContext();
if (context)
{
if (context->getClientVersion() < 3)
if (!context->skipValidation() && !ValidateDrawBuffers(context, n, bufs))
{
context->recordError(Error(GL_INVALID_OPERATION));
return;
}
DrawBuffersEXT(n, bufs);
context->drawBuffers(n, bufs);
}
}
......@@ -664,35 +647,15 @@ void GL_APIENTRY BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint sr
Context *context = GetValidGlobalContext();
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;
}
if (!ValidateBlitFramebufferParameters(context, srcX0, srcY0, srcX1, srcY1,
dstX0, dstY0, dstX1, dstY1, mask, 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;
}
context->blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask,
filter);
}
}
......@@ -728,37 +691,13 @@ void GL_APIENTRY FramebufferTextureLayer(GLenum target, GLenum attachment, GLuin
Context *context = GetValidGlobalContext();
if (context)
{
if (!ValidateFramebufferTextureLayer(context, target, attachment, texture,
level, layer))
if (!context->skipValidation() &&
!ValidateFramebufferTextureLayer(context, target, attachment, texture, level, layer))
{
return;
}
Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
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);
}
context->framebufferTextureLayer(target, attachment, texture, level, layer);
}
}
......@@ -1674,43 +1613,13 @@ void GL_APIENTRY ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* val
Context *context = GetValidGlobalContext();
if (context)
{
if (!ValidateClearBuffer(context))
if (!context->skipValidation() &&
!ValidateClearBufferiv(context, buffer, drawbuffer, value))
{
return;
}
switch (buffer)
{
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;
}
context->clearBufferiv(buffer, drawbuffer, value);
}
}
......@@ -1722,35 +1631,13 @@ void GL_APIENTRY ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* v
Context *context = GetValidGlobalContext();
if (context)
{
if (!ValidateClearBuffer(context))
if (!context->skipValidation() &&
!ValidateClearBufferuiv(context, buffer, drawbuffer, value))
{
return;
}
switch (buffer)
{
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;
}
context->clearBufferuiv(buffer, drawbuffer, value);
}
}
......@@ -1762,43 +1649,13 @@ void GL_APIENTRY ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* v
Context *context = GetValidGlobalContext();
if (context)
{
if (!ValidateClearBuffer(context))
if (!context->skipValidation() &&
!ValidateClearBufferfv(context, buffer, drawbuffer, value))
{
return;
}
switch (buffer)
{
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;
}
context->clearBufferfv(buffer, drawbuffer, value);
}
}
......@@ -1810,41 +1667,13 @@ void GL_APIENTRY ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, G
Context *context = GetValidGlobalContext();
if (context)
{
if (!ValidateClearBuffer(context))
{
return;
}
switch (buffer)
if (!context->skipValidation() &&
!ValidateClearBufferfi(context, buffer, drawbuffer, depth, stencil))
{
case GL_DEPTH_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);
// 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;
}
context->clearBufferfi(buffer, drawbuffer, depth, stencil);
}
}
......@@ -3150,23 +2979,13 @@ void GL_APIENTRY InvalidateFramebuffer(GLenum target, GLsizei numAttachments, co
Context *context = GetValidGlobalContext();
if (context)
{
if (!ValidateInvalidateFramebuffer(context, target, numAttachments, attachments))
if (!context->skipValidation() &&
!ValidateInvalidateFramebuffer(context, target, numAttachments, attachments))
{
return;
}
Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
ASSERT(framebuffer);
if (framebuffer->checkStatus(context->getData()) == GL_FRAMEBUFFER_COMPLETE)
{
Error error = framebuffer->invalidate(numAttachments, attachments);
if (error.isError())
{
context->recordError(error);
return;
}
}
context->invalidateFramebuffer(target, numAttachments, attachments);
}
}
......@@ -3179,24 +2998,13 @@ void GL_APIENTRY InvalidateSubFramebuffer(GLenum target, GLsizei numAttachments,
Context *context = GetValidGlobalContext();
if (context)
{
if (!ValidateInvalidateFramebuffer(context, target, numAttachments, attachments))
if (!context->skipValidation() &&
!ValidateInvalidateFramebuffer(context, target, numAttachments, attachments))
{
return;
}
Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
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;
}
}
context->invalidateSubFramebuffer(target, numAttachments, attachments, x, y, width, height);
}
}
......
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