diff options
Diffstat (limited to 'src/3rdparty/angle/src/libANGLE/validationES2.cpp')
-rw-r--r-- | src/3rdparty/angle/src/libANGLE/validationES2.cpp | 922 |
1 files changed, 898 insertions, 24 deletions
diff --git a/src/3rdparty/angle/src/libANGLE/validationES2.cpp b/src/3rdparty/angle/src/libANGLE/validationES2.cpp index 9eece1b54a..2e5b955e99 100644 --- a/src/3rdparty/angle/src/libANGLE/validationES2.cpp +++ b/src/3rdparty/angle/src/libANGLE/validationES2.cpp @@ -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) @@ -31,7 +67,7 @@ bool ValidateES2TexImageParameters(Context *context, GLenum target, GLint level, return false; } - if (!ValidImageSize(context, target, level, width, height, 1)) + if (!ValidImageSizeParameters(context, target, level, width, height, 1, isSubImage)) { context->recordError(Error(GL_INVALID_VALUE)); return false; @@ -110,7 +146,7 @@ bool ValidateES2TexImageParameters(Context *context, GLenum target, GLint level, } else { - if (texture->isImmutable()) + if (texture->getImmutableFormat()) { context->recordError(Error(GL_INVALID_OPERATION)); return false; @@ -124,23 +160,10 @@ bool ValidateES2TexImageParameters(Context *context, GLenum target, GLint level, return false; } - GLenum actualInternalFormat = isSubImage ? texture->getInternalFormat(target, level) : internalformat; - const InternalFormat &actualFormatInfo = GetInternalFormatInfo(actualInternalFormat); - - if (isCompressed != actualFormatInfo.compressed) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - if (isCompressed) { - if (!ValidCompressedImageSize(context, actualInternalFormat, width, height)) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - + GLenum actualInternalFormat = + isSubImage ? texture->getInternalFormat(target, level) : internalformat; switch (actualInternalFormat) { case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: @@ -165,8 +188,29 @@ bool ValidateES2TexImageParameters(Context *context, GLenum target, GLint level, return false; } break; + case GL_ETC1_RGB8_OES: + if (!context->getExtensions().compressedETC1RGB8Texture) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE: + if (!context->getExtensions().lossyETCDecode) + { + context->recordError( + Error(GL_INVALID_ENUM, "ANGLE_lossy_etc_decode extension is not supported")); + return false; + } + break; default: - context->recordError(Error(GL_INVALID_ENUM)); + context->recordError(Error( + GL_INVALID_ENUM, "internalformat is not a supported compressed internal format")); + return false; + } + if (!ValidCompressedImageSize(context, actualInternalFormat, width, height)) + { + context->recordError(Error(GL_INVALID_OPERATION)); return false; } } @@ -350,6 +394,33 @@ bool ValidateES2TexImageParameters(Context *context, GLenum target, GLint level, return false; } break; + case GL_ETC1_RGB8_OES: + if (context->getExtensions().compressedETC1RGB8Texture) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + else + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE: + if (context->getExtensions().lossyETCDecode) + { + context->recordError( + Error(GL_INVALID_OPERATION, + "ETC1_RGB8_LOSSY_DECODE_ANGLE can't work with this type.")); + return false; + } + else + { + context->recordError( + Error(GL_INVALID_ENUM, "ANGLE_lossy_etc_decode extension is not supported.")); + return false; + } + break; case GL_DEPTH_COMPONENT: case GL_DEPTH_STENCIL_OES: if (!context->getExtensions().depthTextures) @@ -395,21 +466,34 @@ 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; + if (!ValidTexture2DDestinationTarget(context, target)) + { + context->recordError(Error(GL_INVALID_ENUM, "Invalid texture target")); + return false; + } + if (!ValidateCopyTexImageParametersBase(context, target, level, internalformat, isSubImage, xoffset, yoffset, 0, x, y, width, height, border, &textureInternalFormat)) { 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; @@ -502,6 +586,8 @@ bool ValidateES2CopyTexImageParameters(Context* context, GLenum target, GLint le case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + case GL_ETC1_RGB8_OES: + case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE: context->recordError(Error(GL_INVALID_OPERATION)); return false; case GL_DEPTH_COMPONENT: @@ -642,6 +728,32 @@ bool ValidateES2CopyTexImageParameters(Context* context, GLenum target, GLint le return false; } break; + case GL_ETC1_RGB8_OES: + if (context->getExtensions().compressedETC1RGB8Texture) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + else + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE: + if (context->getExtensions().lossyETCDecode) + { + context->recordError(Error(GL_INVALID_OPERATION, + "ETC1_RGB8_LOSSY_DECODE_ANGLE can't be copied to.")); + return false; + } + else + { + context->recordError( + Error(GL_INVALID_ENUM, "ANGLE_lossy_etc_decode extension is not supported.")); + return false; + } + break; case GL_DEPTH_COMPONENT: case GL_DEPTH_COMPONENT16: case GL_DEPTH_COMPONENT32_OES: @@ -759,6 +871,21 @@ bool ValidateES2TexStorageParameters(Context *context, GLenum target, GLsizei le return false; } break; + case GL_ETC1_RGB8_OES: + if (!context->getExtensions().compressedETC1RGB8Texture) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE: + if (!context->getExtensions().lossyETCDecode) + { + context->recordError( + Error(GL_INVALID_ENUM, "ANGLE_lossy_etc_decode extension is not supported.")); + return false; + } + break; case GL_RGBA32F_EXT: case GL_RGB32F_EXT: case GL_ALPHA32F_EXT: @@ -824,7 +951,7 @@ bool ValidateES2TexStorageParameters(Context *context, GLenum target, GLsizei le return false; } - if (texture->isImmutable()) + if (texture->getImmutableFormat()) { context->recordError(Error(GL_INVALID_OPERATION)); return false; @@ -879,4 +1006,751 @@ bool ValidES2ReadFormatType(Context *context, GLenum format, GLenum type) return true; } +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) + { + case GL_FRAMEBUFFER: + defaultFramebuffer = (context->getState().getTargetFramebuffer(GL_FRAMEBUFFER)->id() == 0); + break; + default: + context->recordError(Error(GL_INVALID_ENUM, "Invalid framebuffer target")); + return false; + } + + return ValidateDiscardFramebufferBase(context, target, numAttachments, attachments, defaultFramebuffer); +} + +bool ValidateBindVertexArrayOES(Context *context, GLuint array) +{ + if (!context->getExtensions().vertexArrayObject) + { + context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); + return false; + } + + return ValidateBindVertexArrayBase(context, array); +} + +bool ValidateDeleteVertexArraysOES(Context *context, GLsizei n) +{ + if (!context->getExtensions().vertexArrayObject) + { + context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); + return false; + } + + return ValidateDeleteVertexArraysBase(context, n); +} + +bool ValidateGenVertexArraysOES(Context *context, GLsizei n) +{ + if (!context->getExtensions().vertexArrayObject) + { + context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); + return false; + } + + return ValidateGenVertexArraysBase(context, n); +} + +bool ValidateIsVertexArrayOES(Context *context) +{ + if (!context->getExtensions().vertexArrayObject) + { + context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); + return false; + } + + return true; +} + +bool ValidateProgramBinaryOES(Context *context, + GLuint program, + GLenum binaryFormat, + const void *binary, + GLint length) +{ + if (!context->getExtensions().getProgramBinary) + { + context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); + return false; + } + + return ValidateProgramBinaryBase(context, program, binaryFormat, binary, length); +} + +bool ValidateGetProgramBinaryOES(Context *context, + GLuint program, + GLsizei bufSize, + GLsizei *length, + GLenum *binaryFormat, + void *binary) +{ + if (!context->getExtensions().getProgramBinary) + { + context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); + return false; + } + + return ValidateGetProgramBinaryBase(context, program, bufSize, length, binaryFormat, binary); +} + +static bool ValidDebugSource(GLenum source, bool mustBeThirdPartyOrApplication) +{ + switch (source) + { + case GL_DEBUG_SOURCE_API: + case GL_DEBUG_SOURCE_SHADER_COMPILER: + case GL_DEBUG_SOURCE_WINDOW_SYSTEM: + case GL_DEBUG_SOURCE_OTHER: + // Only THIRD_PARTY and APPLICATION sources are allowed to be manually inserted + return !mustBeThirdPartyOrApplication; + + case GL_DEBUG_SOURCE_THIRD_PARTY: + case GL_DEBUG_SOURCE_APPLICATION: + return true; + + default: + return false; + } +} + +static bool ValidDebugType(GLenum type) +{ + switch (type) + { + case GL_DEBUG_TYPE_ERROR: + case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: + case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: + case GL_DEBUG_TYPE_PERFORMANCE: + case GL_DEBUG_TYPE_PORTABILITY: + case GL_DEBUG_TYPE_OTHER: + case GL_DEBUG_TYPE_MARKER: + case GL_DEBUG_TYPE_PUSH_GROUP: + case GL_DEBUG_TYPE_POP_GROUP: + return true; + + default: + return false; + } +} + +static bool ValidDebugSeverity(GLenum severity) +{ + switch (severity) + { + case GL_DEBUG_SEVERITY_HIGH: + case GL_DEBUG_SEVERITY_MEDIUM: + case GL_DEBUG_SEVERITY_LOW: + case GL_DEBUG_SEVERITY_NOTIFICATION: + return true; + + default: + return false; + } +} + +bool ValidateDebugMessageControlKHR(Context *context, + GLenum source, + GLenum type, + GLenum severity, + GLsizei count, + const GLuint *ids, + GLboolean enabled) +{ + if (!context->getExtensions().debug) + { + context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); + return false; + } + + if (!ValidDebugSource(source, false) && source != GL_DONT_CARE) + { + context->recordError(Error(GL_INVALID_ENUM, "Invalid debug source.")); + return false; + } + + if (!ValidDebugType(type) && type != GL_DONT_CARE) + { + context->recordError(Error(GL_INVALID_ENUM, "Invalid debug type.")); + return false; + } + + if (!ValidDebugSeverity(severity) && severity != GL_DONT_CARE) + { + context->recordError(Error(GL_INVALID_ENUM, "Invalid debug severity.")); + return false; + } + + if (count > 0) + { + if (source == GL_DONT_CARE || type == GL_DONT_CARE) + { + context->recordError(Error( + GL_INVALID_OPERATION, + "If count is greater than zero, source and severity cannot be GL_DONT_CARE.")); + return false; + } + + if (severity != GL_DONT_CARE) + { + context->recordError( + Error(GL_INVALID_OPERATION, + "If count is greater than zero, severity must be GL_DONT_CARE.")); + return false; + } + } + + return true; +} + +bool ValidateDebugMessageInsertKHR(Context *context, + GLenum source, + GLenum type, + GLuint id, + GLenum severity, + GLsizei length, + const GLchar *buf) +{ + if (!context->getExtensions().debug) + { + context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); + return false; + } + + if (!context->getState().getDebug().isOutputEnabled()) + { + // If the DEBUG_OUTPUT state is disabled calls to DebugMessageInsert are discarded and do + // not generate an error. + return false; + } + + if (!ValidDebugSeverity(severity)) + { + context->recordError(Error(GL_INVALID_ENUM, "Invalid debug severity.")); + return false; + } + + if (!ValidDebugType(type)) + { + context->recordError(Error(GL_INVALID_ENUM, "Invalid debug type.")); + return false; + } + + if (!ValidDebugSource(source, true)) + { + context->recordError(Error(GL_INVALID_ENUM, "Invalid debug source.")); + return false; + } + + size_t messageLength = (length < 0) ? strlen(buf) : length; + if (messageLength > context->getExtensions().maxDebugMessageLength) + { + context->recordError( + Error(GL_INVALID_VALUE, "Message length is larger than GL_MAX_DEBUG_MESSAGE_LENGTH.")); + return false; + } + + return true; +} + +bool ValidateDebugMessageCallbackKHR(Context *context, + GLDEBUGPROCKHR callback, + const void *userParam) +{ + if (!context->getExtensions().debug) + { + context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); + return false; + } + + return true; +} + +bool ValidateGetDebugMessageLogKHR(Context *context, + GLuint count, + GLsizei bufSize, + GLenum *sources, + GLenum *types, + GLuint *ids, + GLenum *severities, + GLsizei *lengths, + GLchar *messageLog) +{ + if (!context->getExtensions().debug) + { + context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); + return false; + } + + if (bufSize < 0 && messageLog != nullptr) + { + context->recordError( + Error(GL_INVALID_VALUE, "bufSize must be positive if messageLog is not null.")); + return false; + } + + return true; +} + +bool ValidatePushDebugGroupKHR(Context *context, + GLenum source, + GLuint id, + GLsizei length, + const GLchar *message) +{ + if (!context->getExtensions().debug) + { + context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); + return false; + } + + if (!ValidDebugSource(source, true)) + { + context->recordError(Error(GL_INVALID_ENUM, "Invalid debug source.")); + return false; + } + + size_t messageLength = (length < 0) ? strlen(message) : length; + if (messageLength > context->getExtensions().maxDebugMessageLength) + { + context->recordError( + Error(GL_INVALID_VALUE, "Message length is larger than GL_MAX_DEBUG_MESSAGE_LENGTH.")); + return false; + } + + size_t currentStackSize = context->getState().getDebug().getGroupStackDepth(); + if (currentStackSize >= context->getExtensions().maxDebugGroupStackDepth) + { + context->recordError( + Error(GL_STACK_OVERFLOW, + "Cannot push more than GL_MAX_DEBUG_GROUP_STACK_DEPTH debug groups.")); + return false; + } + + return true; +} + +bool ValidatePopDebugGroupKHR(Context *context) +{ + if (!context->getExtensions().debug) + { + context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); + return false; + } + + size_t currentStackSize = context->getState().getDebug().getGroupStackDepth(); + if (currentStackSize <= 1) + { + context->recordError(Error(GL_STACK_UNDERFLOW, "Cannot pop the default debug group.")); + return false; + } + + return true; +} + +static bool ValidateObjectIdentifierAndName(Context *context, GLenum identifier, GLuint name) +{ + switch (identifier) + { + case GL_BUFFER: + if (context->getBuffer(name) == nullptr) + { + context->recordError(Error(GL_INVALID_VALUE, "name is not a valid buffer.")); + return false; + } + return true; + + case GL_SHADER: + if (context->getShader(name) == nullptr) + { + context->recordError(Error(GL_INVALID_VALUE, "name is not a valid shader.")); + return false; + } + return true; + + case GL_PROGRAM: + if (context->getProgram(name) == nullptr) + { + context->recordError(Error(GL_INVALID_VALUE, "name is not a valid program.")); + return false; + } + return true; + + case GL_VERTEX_ARRAY: + if (context->getVertexArray(name) == nullptr) + { + context->recordError(Error(GL_INVALID_VALUE, "name is not a valid vertex array.")); + return false; + } + return true; + + case GL_QUERY: + if (context->getQuery(name) == nullptr) + { + context->recordError(Error(GL_INVALID_VALUE, "name is not a valid query.")); + return false; + } + return true; + + case GL_TRANSFORM_FEEDBACK: + if (context->getTransformFeedback(name) == nullptr) + { + context->recordError( + Error(GL_INVALID_VALUE, "name is not a valid transform feedback.")); + return false; + } + return true; + + case GL_SAMPLER: + if (context->getSampler(name) == nullptr) + { + context->recordError(Error(GL_INVALID_VALUE, "name is not a valid sampler.")); + return false; + } + return true; + + case GL_TEXTURE: + if (context->getTexture(name) == nullptr) + { + context->recordError(Error(GL_INVALID_VALUE, "name is not a valid texture.")); + return false; + } + return true; + + case GL_RENDERBUFFER: + if (context->getRenderbuffer(name) == nullptr) + { + context->recordError(Error(GL_INVALID_VALUE, "name is not a valid renderbuffer.")); + return false; + } + return true; + + case GL_FRAMEBUFFER: + if (context->getFramebuffer(name) == nullptr) + { + context->recordError(Error(GL_INVALID_VALUE, "name is not a valid framebuffer.")); + return false; + } + return true; + + default: + context->recordError(Error(GL_INVALID_ENUM, "Invalid identifier.")); + return false; + } + + return true; +} + +bool ValidateObjectLabelKHR(Context *context, + GLenum identifier, + GLuint name, + GLsizei length, + const GLchar *label) +{ + if (!context->getExtensions().debug) + { + context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); + return false; + } + + if (!ValidateObjectIdentifierAndName(context, identifier, name)) + { + return false; + } + + size_t labelLength = (length < 0) ? strlen(label) : length; + if (labelLength > context->getExtensions().maxLabelLength) + { + context->recordError( + Error(GL_INVALID_VALUE, "Label length is larger than GL_MAX_LABEL_LENGTH.")); + return false; + } + + return true; +} + +bool ValidateGetObjectLabelKHR(Context *context, + GLenum identifier, + GLuint name, + GLsizei bufSize, + GLsizei *length, + GLchar *label) +{ + if (!context->getExtensions().debug) + { + context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); + return false; + } + + if (bufSize < 0) + { + context->recordError(Error(GL_INVALID_VALUE, "bufSize cannot be negative.")); + return false; + } + + if (!ValidateObjectIdentifierAndName(context, identifier, name)) + { + return false; + } + + // Can no-op if bufSize is zero. + return bufSize > 0; +} + +static bool ValidateObjectPtrName(Context *context, const void *ptr) +{ + if (context->getFenceSync(reinterpret_cast<GLsync>(const_cast<void *>(ptr))) == nullptr) + { + context->recordError(Error(GL_INVALID_VALUE, "name is not a valid sync.")); + return false; + } + + return true; +} + +bool ValidateObjectPtrLabelKHR(Context *context, + const void *ptr, + GLsizei length, + const GLchar *label) +{ + if (!context->getExtensions().debug) + { + context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); + return false; + } + + if (!ValidateObjectPtrName(context, ptr)) + { + return false; + } + + size_t labelLength = (length < 0) ? strlen(label) : length; + if (labelLength > context->getExtensions().maxLabelLength) + { + context->recordError( + Error(GL_INVALID_VALUE, "Label length is larger than GL_MAX_LABEL_LENGTH.")); + return false; + } + + return true; +} + +bool ValidateGetObjectPtrLabelKHR(Context *context, + const void *ptr, + GLsizei bufSize, + GLsizei *length, + GLchar *label) +{ + if (!context->getExtensions().debug) + { + context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); + return false; + } + + if (bufSize < 0) + { + context->recordError(Error(GL_INVALID_VALUE, "bufSize cannot be negative.")); + return false; + } + + if (!ValidateObjectPtrName(context, ptr)) + { + return false; + } + + // Can no-op if bufSize is zero. + return bufSize > 0; +} + +bool ValidateGetPointervKHR(Context *context, GLenum pname, void **params) +{ + if (!context->getExtensions().debug) + { + context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled")); + return false; + } + + // TODO: represent this in Context::getQueryParameterInfo. + switch (pname) + { + case GL_DEBUG_CALLBACK_FUNCTION: + case GL_DEBUG_CALLBACK_USER_PARAM: + break; + + default: + context->recordError(Error(GL_INVALID_ENUM, "Invalid pname.")); + return false; + } + + 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 drawbufferIdx = 0; + drawbufferIdx < drawFramebuffer->getDrawbufferStateCount(); ++drawbufferIdx) + { + const FramebufferAttachment *attachment = + drawFramebuffer->getDrawBuffer(drawbufferIdx); + if (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 |