Commit dfc20daf by Jamie Madill Committed by Commit Bot

Plumb more logic for ANGLE_get_image.

Also implements and tests validation / negative API. Bug: angleproject:3944 Change-Id: I3385a4255f4fab6a12eee2abfa5ffcce2107359a Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1879961 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarCody Northrop <cnorthrop@google.com>
parent 2f71802b
...@@ -896,6 +896,7 @@ const ExtensionInfoMap &GetExtensionInfoMap() ...@@ -896,6 +896,7 @@ const ExtensionInfoMap &GetExtensionInfoMap()
map["GL_CHROMIUM_lose_context"] = enableableExtension(&Extensions::loseContextCHROMIUM); map["GL_CHROMIUM_lose_context"] = enableableExtension(&Extensions::loseContextCHROMIUM);
map["GL_ANGLE_texture_external_update"] = enableableExtension(&Extensions::textureExternalUpdateANGLE); map["GL_ANGLE_texture_external_update"] = enableableExtension(&Extensions::textureExternalUpdateANGLE);
map["GL_ANGLE_base_vertex_base_instance"] = enableableExtension(&Extensions::baseVertexBaseInstance); map["GL_ANGLE_base_vertex_base_instance"] = enableableExtension(&Extensions::baseVertexBaseInstance);
map["GL_ANGLE_get_image"] = enableableExtension(&Extensions::getImageANGLE);
// GLES1 extensinos // GLES1 extensinos
map["GL_OES_point_size_array"] = enableableExtension(&Extensions::pointSizeArray); map["GL_OES_point_size_array"] = enableableExtension(&Extensions::pointSizeArray);
map["GL_OES_texture_cube_map"] = enableableExtension(&Extensions::textureCubeMap); map["GL_OES_texture_cube_map"] = enableableExtension(&Extensions::textureCubeMap);
......
...@@ -541,6 +541,9 @@ struct Extensions ...@@ -541,6 +541,9 @@ struct Extensions
// GL_ANGLE_base_vertex_base_instance // GL_ANGLE_base_vertex_base_instance
bool baseVertexBaseInstance = false; bool baseVertexBaseInstance = false;
// GL_ANGLE_get_image
bool getImageANGLE = false;
}; };
// Pointer to a boolean memeber of the Extensions struct // Pointer to a boolean memeber of the Extensions struct
......
...@@ -2108,7 +2108,7 @@ void Context::texBufferRange(GLenum target, ...@@ -2108,7 +2108,7 @@ void Context::texBufferRange(GLenum target,
void Context::getTexParameterfv(TextureType target, GLenum pname, GLfloat *params) void Context::getTexParameterfv(TextureType target, GLenum pname, GLfloat *params)
{ {
const Texture *const texture = getTextureByType(target); const Texture *const texture = getTextureByType(target);
QueryTexParameterfv(texture, pname, params); QueryTexParameterfv(this, texture, pname, params);
} }
void Context::getTexParameterfvRobust(TextureType target, void Context::getTexParameterfvRobust(TextureType target,
...@@ -2123,19 +2123,19 @@ void Context::getTexParameterfvRobust(TextureType target, ...@@ -2123,19 +2123,19 @@ void Context::getTexParameterfvRobust(TextureType target,
void Context::getTexParameteriv(TextureType target, GLenum pname, GLint *params) void Context::getTexParameteriv(TextureType target, GLenum pname, GLint *params)
{ {
const Texture *const texture = getTextureByType(target); const Texture *const texture = getTextureByType(target);
QueryTexParameteriv(texture, pname, params); QueryTexParameteriv(this, texture, pname, params);
} }
void Context::getTexParameterIiv(TextureType target, GLenum pname, GLint *params) void Context::getTexParameterIiv(TextureType target, GLenum pname, GLint *params)
{ {
const Texture *const texture = getTextureByType(target); const Texture *const texture = getTextureByType(target);
QueryTexParameterIiv(texture, pname, params); QueryTexParameterIiv(this, texture, pname, params);
} }
void Context::getTexParameterIuiv(TextureType target, GLenum pname, GLuint *params) void Context::getTexParameterIuiv(TextureType target, GLenum pname, GLuint *params)
{ {
const Texture *const texture = getTextureByType(target); const Texture *const texture = getTextureByType(target);
QueryTexParameterIuiv(texture, pname, params); QueryTexParameterIuiv(this, texture, pname, params);
} }
void Context::getTexParameterivRobust(TextureType target, void Context::getTexParameterivRobust(TextureType target,
...@@ -9204,12 +9204,18 @@ void Context::getTexImage(TextureTarget target, ...@@ -9204,12 +9204,18 @@ void Context::getTexImage(TextureTarget target,
GLenum type, GLenum type,
void *pixels) void *pixels)
{ {
UNIMPLEMENTED(); Texture *texture = getTextureByTarget(target);
Buffer *packBuffer = mState.getTargetBuffer(BufferBinding::PixelPack);
ANGLE_CONTEXT_TRY(texture->getTexImage(this, mState.getPackState(), packBuffer, target, level,
format, type, pixels));
} }
void Context::getRenderbufferImage(GLenum target, GLenum format, GLenum type, void *pixels) void Context::getRenderbufferImage(GLenum target, GLenum format, GLenum type, void *pixels)
{ {
UNIMPLEMENTED(); Renderbuffer *renderbuffer = mState.getCurrentRenderbuffer();
Buffer *packBuffer = mState.getTargetBuffer(BufferBinding::PixelPack);
ANGLE_CONTEXT_TRY(renderbuffer->getRenderbufferImage(this, mState.getPackState(), packBuffer,
format, type, pixels));
} }
// ErrorSet implementation. // ErrorSet implementation.
......
...@@ -137,6 +137,7 @@ MSG kFramebufferTextureLayerIncorrectTextureType = "Texture is not a three-dimen ...@@ -137,6 +137,7 @@ MSG kFramebufferTextureLayerIncorrectTextureType = "Texture is not a three-dimen
MSG kGenerateMipmapNotAllowed = "Texture format does not support mipmap generation."; MSG kGenerateMipmapNotAllowed = "Texture format does not support mipmap generation.";
MSG kGenerateMipmapZeroSize = "Cannot generate mipmaps for a zero-size texture in a WebGL context."; MSG kGenerateMipmapZeroSize = "Cannot generate mipmaps for a zero-size texture in a WebGL context.";
MSG kGeometryShaderExtensionNotEnabled = "GL_EXT_geometry_shader extension not enabled."; MSG kGeometryShaderExtensionNotEnabled = "GL_EXT_geometry_shader extension not enabled.";
MSG kGetImageExtensionNotEnabled = "GL_ANGLE_get_image extension not enabled.";
MSG kGLES1Only = "GLES1-only function."; MSG kGLES1Only = "GLES1-only function.";
MSG kImageSizeMustBeZero = "imageSize must be 0 if no texture data is provided."; MSG kImageSizeMustBeZero = "imageSize must be 0 if no texture data is provided.";
MSG kImageSizeTooSmall = "imageSize is too small."; MSG kImageSizeTooSmall = "imageSize is too small.";
......
...@@ -280,4 +280,24 @@ rx::FramebufferAttachmentObjectImpl *Renderbuffer::getAttachmentImpl() const ...@@ -280,4 +280,24 @@ rx::FramebufferAttachmentObjectImpl *Renderbuffer::getAttachmentImpl() const
return mImplementation.get(); return mImplementation.get();
} }
GLenum Renderbuffer::getImplementationColorReadFormat(const Context *context) const
{
return mImplementation->getColorReadFormat(context);
}
GLenum Renderbuffer::getImplementationColorReadType(const Context *context) const
{
return mImplementation->getColorReadType(context);
}
angle::Result Renderbuffer::getRenderbufferImage(const Context *context,
const PixelPackState &packState,
Buffer *packBuffer,
GLenum format,
GLenum type,
void *pixels) const
{
return mImplementation->getRenderbufferImage(context, packState, packBuffer, format, type,
pixels);
}
} // namespace gl } // namespace gl
...@@ -115,6 +115,17 @@ class Renderbuffer final : public RefCountObject<RenderbufferID>, ...@@ -115,6 +115,17 @@ class Renderbuffer final : public RefCountObject<RenderbufferID>,
InitState initState(const ImageIndex &imageIndex) const override; InitState initState(const ImageIndex &imageIndex) const override;
void setInitState(const ImageIndex &imageIndex, InitState initState) override; void setInitState(const ImageIndex &imageIndex, InitState initState) override;
GLenum getImplementationColorReadFormat(const Context *context) const;
GLenum getImplementationColorReadType(const Context *context) const;
// We pass the pack buffer and state explicitly so they can be overridden during capture.
angle::Result getRenderbufferImage(const Context *context,
const PixelPackState &packState,
Buffer *packBuffer,
GLenum format,
GLenum type,
void *pixels) const;
private: private:
rx::FramebufferAttachmentObjectImpl *getAttachmentImpl() const override; rx::FramebufferAttachmentObjectImpl *getAttachmentImpl() const override;
......
...@@ -1886,4 +1886,26 @@ void Texture::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMess ...@@ -1886,4 +1886,26 @@ void Texture::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMess
} }
} }
GLenum Texture::getImplementationColorReadFormat(const Context *context) const
{
return mTexture->getColorReadFormat(context);
}
GLenum Texture::getImplementationColorReadType(const Context *context) const
{
return mTexture->getColorReadType(context);
}
angle::Result Texture::getTexImage(const Context *context,
const PixelPackState &packState,
Buffer *packBuffer,
TextureTarget target,
GLint level,
GLenum format,
GLenum type,
void *pixels) const
{
return mTexture->getTexImage(context, packState, packBuffer, target, level, format, type,
pixels);
}
} // namespace gl } // namespace gl
...@@ -423,6 +423,19 @@ class Texture final : public RefCountObject<TextureID>, ...@@ -423,6 +423,19 @@ class Texture final : public RefCountObject<TextureID>,
bool isSamplerComplete(const Context *context, const Sampler *optionalSampler); bool isSamplerComplete(const Context *context, const Sampler *optionalSampler);
GLenum getImplementationColorReadFormat(const Context *context) const;
GLenum getImplementationColorReadType(const Context *context) const;
// We pass the pack buffer and state explicitly so they can be overridden during capture.
angle::Result getTexImage(const Context *context,
const PixelPackState &packState,
Buffer *packBuffer,
TextureTarget target,
GLint level,
GLenum format,
GLenum type,
void *pixels) const;
rx::TextureImpl *getImplementation() const { return mTexture; } rx::TextureImpl *getImplementation() const { return mTexture; }
// FramebufferAttachmentObject implementation // FramebufferAttachmentObject implementation
......
...@@ -218,7 +218,10 @@ void QueryTexLevelParameterBase(const Texture *texture, ...@@ -218,7 +218,10 @@ void QueryTexLevelParameterBase(const Texture *texture,
} }
template <bool isPureInteger, typename ParamType> template <bool isPureInteger, typename ParamType>
void QueryTexParameterBase(const Texture *texture, GLenum pname, ParamType *params) void QueryTexParameterBase(const Context *context,
const Texture *texture,
GLenum pname,
ParamType *params)
{ {
ASSERT(texture != nullptr); ASSERT(texture != nullptr);
...@@ -309,6 +312,14 @@ void QueryTexParameterBase(const Texture *texture, GLenum pname, ParamType *para ...@@ -309,6 +312,14 @@ void QueryTexParameterBase(const Texture *texture, GLenum pname, ParamType *para
case GL_TEXTURE_NATIVE_ID_ANGLE: case GL_TEXTURE_NATIVE_ID_ANGLE:
*params = CastFromStateValue<ParamType>(pname, texture->getNativeID()); *params = CastFromStateValue<ParamType>(pname, texture->getNativeID());
break; break;
case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
*params = CastFromGLintStateValue<ParamType>(
pname, texture->getImplementationColorReadFormat(context));
break;
case GL_IMPLEMENTATION_COLOR_READ_TYPE:
*params = CastFromGLintStateValue<ParamType>(
pname, texture->getImplementationColorReadType(context));
break;
default: default:
UNREACHABLE(); UNREACHABLE();
break; break;
...@@ -997,7 +1008,7 @@ bool IsTextureEnvEnumParameter(TextureEnvParameter pname) ...@@ -997,7 +1008,7 @@ bool IsTextureEnvEnumParameter(TextureEnvParameter pname)
} }
} }
} // anonymous namespace } // namespace
void QueryFramebufferAttachmentParameteriv(const Context *context, void QueryFramebufferAttachmentParameteriv(const Context *context,
const Framebuffer *framebuffer, const Framebuffer *framebuffer,
...@@ -1303,6 +1314,12 @@ void QueryRenderbufferiv(const Context *context, ...@@ -1303,6 +1314,12 @@ void QueryRenderbufferiv(const Context *context,
case GL_MEMORY_SIZE_ANGLE: case GL_MEMORY_SIZE_ANGLE:
*params = renderbuffer->getMemorySize(); *params = renderbuffer->getMemorySize();
break; break;
case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
*params = static_cast<GLint>(renderbuffer->getImplementationColorReadFormat(context));
break;
case GL_IMPLEMENTATION_COLOR_READ_TYPE:
*params = static_cast<GLint>(renderbuffer->getImplementationColorReadType(context));
break;
default: default:
UNREACHABLE(); UNREACHABLE();
break; break;
...@@ -1367,24 +1384,36 @@ void QueryTexLevelParameteriv(const Texture *texture, ...@@ -1367,24 +1384,36 @@ void QueryTexLevelParameteriv(const Texture *texture,
QueryTexLevelParameterBase(texture, target, level, pname, params); QueryTexLevelParameterBase(texture, target, level, pname, params);
} }
void QueryTexParameterfv(const Texture *texture, GLenum pname, GLfloat *params) void QueryTexParameterfv(const Context *context,
const Texture *texture,
GLenum pname,
GLfloat *params)
{ {
QueryTexParameterBase<false>(texture, pname, params); QueryTexParameterBase<false>(context, texture, pname, params);
} }
void QueryTexParameteriv(const Texture *texture, GLenum pname, GLint *params) void QueryTexParameteriv(const Context *context,
const Texture *texture,
GLenum pname,
GLint *params)
{ {
QueryTexParameterBase<false>(texture, pname, params); QueryTexParameterBase<false>(context, texture, pname, params);
} }
void QueryTexParameterIiv(const Texture *texture, GLenum pname, GLint *params) void QueryTexParameterIiv(const Context *context,
const Texture *texture,
GLenum pname,
GLint *params)
{ {
QueryTexParameterBase<true>(texture, pname, params); QueryTexParameterBase<true>(context, texture, pname, params);
} }
void QueryTexParameterIuiv(const Texture *texture, GLenum pname, GLuint *params) void QueryTexParameterIuiv(const Context *context,
const Texture *texture,
GLenum pname,
GLuint *params)
{ {
QueryTexParameterBase<true>(texture, pname, params); QueryTexParameterBase<true>(context, texture, pname, params);
} }
void QuerySamplerParameterfv(const Sampler *sampler, GLenum pname, GLfloat *params) void QuerySamplerParameterfv(const Sampler *sampler, GLenum pname, GLfloat *params)
......
...@@ -58,10 +58,22 @@ void QueryTexLevelParameteriv(const Texture *texture, ...@@ -58,10 +58,22 @@ void QueryTexLevelParameteriv(const Texture *texture,
GLint level, GLint level,
GLenum pname, GLenum pname,
GLint *params); GLint *params);
void QueryTexParameterfv(const Texture *texture, GLenum pname, GLfloat *params); void QueryTexParameterfv(const Context *context,
void QueryTexParameteriv(const Texture *texture, GLenum pname, GLint *params); const Texture *texture,
void QueryTexParameterIiv(const Texture *texture, GLenum pname, GLint *params); GLenum pname,
void QueryTexParameterIuiv(const Texture *texture, GLenum pname, GLuint *params); GLfloat *params);
void QueryTexParameteriv(const Context *context,
const Texture *texture,
GLenum pname,
GLint *params);
void QueryTexParameterIiv(const Context *context,
const Texture *texture,
GLenum pname,
GLint *params);
void QueryTexParameterIuiv(const Context *context,
const Texture *texture,
GLenum pname,
GLuint *params);
void QuerySamplerParameterfv(const Sampler *sampler, GLenum pname, GLfloat *params); void QuerySamplerParameterfv(const Sampler *sampler, GLenum pname, GLfloat *params);
void QuerySamplerParameteriv(const Sampler *sampler, GLenum pname, GLint *params); void QuerySamplerParameteriv(const Sampler *sampler, GLenum pname, GLint *params);
void QuerySamplerParameterIiv(const Sampler *sampler, GLenum pname, GLint *params); void QuerySamplerParameterIiv(const Sampler *sampler, GLenum pname, GLint *params);
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
namespace gl namespace gl
{ {
struct PixelPackState;
class RenderbufferState; class RenderbufferState;
} // namespace gl } // namespace gl
...@@ -46,6 +47,16 @@ class RenderbufferImpl : public FramebufferAttachmentObjectImpl ...@@ -46,6 +47,16 @@ class RenderbufferImpl : public FramebufferAttachmentObjectImpl
virtual angle::Result setStorageEGLImageTarget(const gl::Context *context, virtual angle::Result setStorageEGLImageTarget(const gl::Context *context,
egl::Image *image) = 0; egl::Image *image) = 0;
virtual GLenum getColorReadFormat(const gl::Context *context);
virtual GLenum getColorReadType(const gl::Context *context);
virtual angle::Result getRenderbufferImage(const gl::Context *context,
const gl::PixelPackState &packState,
gl::Buffer *packBuffer,
GLenum format,
GLenum type,
void *pixels);
// Override if accurate native memory size information is available // Override if accurate native memory size information is available
virtual GLint getMemorySize() const; virtual GLint getMemorySize() const;
...@@ -58,6 +69,28 @@ inline GLint RenderbufferImpl::getMemorySize() const ...@@ -58,6 +69,28 @@ inline GLint RenderbufferImpl::getMemorySize() const
return 0; return 0;
} }
inline GLenum RenderbufferImpl::getColorReadFormat(const gl::Context *context)
{
UNREACHABLE();
return GL_NONE;
}
inline GLenum RenderbufferImpl::getColorReadType(const gl::Context *context)
{
UNREACHABLE();
return GL_NONE;
}
inline angle::Result RenderbufferImpl::getRenderbufferImage(const gl::Context *context,
const gl::PixelPackState &packState,
gl::Buffer *packBuffer,
GLenum format,
GLenum type,
void *pixels)
{
UNREACHABLE();
return angle::Result::Stop;
}
} // namespace rx } // namespace rx
#endif // LIBANGLE_RENDERER_RENDERBUFFERIMPL_H_ #endif // LIBANGLE_RENDERER_RENDERBUFFERIMPL_H_
...@@ -108,4 +108,28 @@ GLint TextureImpl::getNativeID() const ...@@ -108,4 +108,28 @@ GLint TextureImpl::getNativeID() const
return 0; return 0;
} }
GLenum TextureImpl::getColorReadFormat(const gl::Context *context)
{
UNREACHABLE();
return GL_NONE;
}
GLenum TextureImpl::getColorReadType(const gl::Context *context)
{
UNREACHABLE();
return GL_NONE;
}
angle::Result TextureImpl::getTexImage(const gl::Context *context,
const gl::PixelPackState &packState,
gl::Buffer *packBuffer,
gl::TextureTarget target,
GLint level,
GLenum format,
GLenum type,
void *pixels)
{
UNREACHABLE();
return angle::Result::Stop;
}
} // namespace rx } // namespace rx
...@@ -188,6 +188,18 @@ class TextureImpl : public FramebufferAttachmentObjectImpl, public angle::Subjec ...@@ -188,6 +188,18 @@ class TextureImpl : public FramebufferAttachmentObjectImpl, public angle::Subjec
virtual angle::Result syncState(const gl::Context *context, virtual angle::Result syncState(const gl::Context *context,
const gl::Texture::DirtyBits &dirtyBits) = 0; const gl::Texture::DirtyBits &dirtyBits) = 0;
virtual GLenum getColorReadFormat(const gl::Context *context);
virtual GLenum getColorReadType(const gl::Context *context);
virtual angle::Result getTexImage(const gl::Context *context,
const gl::PixelPackState &packState,
gl::Buffer *packBuffer,
gl::TextureTarget target,
GLint level,
GLenum format,
GLenum type,
void *pixels);
protected: protected:
const gl::TextureState &mState; const gl::TextureState &mState;
}; };
......
...@@ -225,4 +225,26 @@ void RenderbufferVk::releaseImage(ContextVk *contextVk) ...@@ -225,4 +225,26 @@ void RenderbufferVk::releaseImage(ContextVk *contextVk)
mImageViews.release(renderer); mImageViews.release(renderer);
} }
GLenum RenderbufferVk::getColorReadFormat(const gl::Context *context)
{
UNIMPLEMENTED();
return GL_NONE;
}
GLenum RenderbufferVk::getColorReadType(const gl::Context *context)
{
UNIMPLEMENTED();
return GL_NONE;
}
angle::Result RenderbufferVk::getRenderbufferImage(const gl::Context *context,
const gl::PixelPackState &packState,
gl::Buffer *packBuffer,
GLenum format,
GLenum type,
void *pixels)
{
UNIMPLEMENTED();
return angle::Result::Continue;
}
} // namespace rx } // namespace rx
...@@ -48,6 +48,16 @@ class RenderbufferVk : public RenderbufferImpl ...@@ -48,6 +48,16 @@ class RenderbufferVk : public RenderbufferImpl
vk::ImageHelper *getImage() const { return mImage; } vk::ImageHelper *getImage() const { return mImage; }
void releaseOwnershipOfImage(const gl::Context *context); void releaseOwnershipOfImage(const gl::Context *context);
GLenum getColorReadFormat(const gl::Context *context) override;
GLenum getColorReadType(const gl::Context *context) override;
angle::Result getRenderbufferImage(const gl::Context *context,
const gl::PixelPackState &packState,
gl::Buffer *packBuffer,
GLenum format,
GLenum type,
void *pixels) override;
private: private:
void releaseAndDeleteImage(ContextVk *contextVk); void releaseAndDeleteImage(ContextVk *contextVk);
void releaseImage(ContextVk *contextVk); void releaseImage(ContextVk *contextVk);
......
...@@ -1269,7 +1269,6 @@ angle::Result TextureVk::ensureImageInitialized(ContextVk *contextVk, ImageMipLe ...@@ -1269,7 +1269,6 @@ angle::Result TextureVk::ensureImageInitialized(ContextVk *contextVk, ImageMipLe
const gl::ImageDesc &baseLevelDesc = mState.getBaseLevelDesc(); const gl::ImageDesc &baseLevelDesc = mState.getBaseLevelDesc();
const gl::Extents &baseLevelExtents = baseLevelDesc.size; const gl::Extents &baseLevelExtents = baseLevelDesc.size;
const uint32_t levelCount = getMipLevelCount(mipLevels); const uint32_t levelCount = getMipLevelCount(mipLevels);
const vk::Format &format = const vk::Format &format =
contextVk->getRenderer()->getFormat(baseLevelDesc.format.info->sizedInternalFormat); contextVk->getRenderer()->getFormat(baseLevelDesc.format.info->sizedInternalFormat);
...@@ -1704,4 +1703,29 @@ angle::Result TextureVk::generateMipmapLevelsWithCPU(ContextVk *contextVk, ...@@ -1704,4 +1703,29 @@ angle::Result TextureVk::generateMipmapLevelsWithCPU(ContextVk *contextVk,
return angle::Result::Continue; return angle::Result::Continue;
} }
GLenum TextureVk::getColorReadFormat(const gl::Context *context)
{
UNIMPLEMENTED();
return GL_NONE;
}
GLenum TextureVk::getColorReadType(const gl::Context *context)
{
UNIMPLEMENTED();
return GL_NONE;
}
angle::Result TextureVk::getTexImage(const gl::Context *context,
const gl::PixelPackState &packState,
gl::Buffer *packBuffer,
gl::TextureTarget target,
GLint level,
GLenum format,
GLenum type,
void *pixels)
{
UNIMPLEMENTED();
return angle::Result::Continue;
}
} // namespace rx } // namespace rx
...@@ -198,6 +198,18 @@ class TextureVk : public TextureImpl ...@@ -198,6 +198,18 @@ class TextureVk : public TextureImpl
mStagingBufferInitialSize = initialSizeForTesting; mStagingBufferInitialSize = initialSizeForTesting;
} }
GLenum getColorReadFormat(const gl::Context *context) override;
GLenum getColorReadType(const gl::Context *context) override;
angle::Result getTexImage(const gl::Context *context,
const gl::PixelPackState &packState,
gl::Buffer *packBuffer,
gl::TextureTarget target,
GLint level,
GLenum format,
GLenum type,
void *pixels) override;
private: private:
// Transform an image index from the frontend into one that can be used on the backing // Transform an image index from the frontend into one that can be used on the backing
// ImageHelper, taking into account mipmap or cube face offsets // ImageHelper, taking into account mipmap or cube face offsets
......
...@@ -69,8 +69,8 @@ void RendererVk::ensureCapsInitialized() const ...@@ -69,8 +69,8 @@ void RendererVk::ensureCapsInitialized() const
// Enable EXT_blend_minmax // Enable EXT_blend_minmax
mNativeExtensions.blendMinMax = true; mNativeExtensions.blendMinMax = true;
mNativeExtensions.eglImage = true; mNativeExtensions.eglImage = true;
mNativeExtensions.eglImageExternal = true; mNativeExtensions.eglImageExternal = true;
mNativeExtensions.eglImageExternalEssl3 = true; mNativeExtensions.eglImageExternalEssl3 = true;
mNativeExtensions.memoryObject = true; mNativeExtensions.memoryObject = true;
...@@ -126,6 +126,9 @@ void RendererVk::ensureCapsInitialized() const ...@@ -126,6 +126,9 @@ void RendererVk::ensureCapsInitialized() const
mNativeExtensions.fboRenderMipmap = true; mNativeExtensions.fboRenderMipmap = true;
// We support getting image data for Textures and Renderbuffers.
mNativeExtensions.getImageANGLE = true;
// https://vulkan.lunarg.com/doc/view/1.0.30.0/linux/vkspec.chunked/ch31s02.html // https://vulkan.lunarg.com/doc/view/1.0.30.0/linux/vkspec.chunked/ch31s02.html
mNativeCaps.maxElementIndex = std::numeric_limits<GLuint>::max() - 1; mNativeCaps.maxElementIndex = std::numeric_limits<GLuint>::max() - 1;
mNativeCaps.max3DTextureSize = limitsVk.maxImageDimension3D; mNativeCaps.max3DTextureSize = limitsVk.maxImageDimension3D;
...@@ -136,8 +139,8 @@ void RendererVk::ensureCapsInitialized() const ...@@ -136,8 +139,8 @@ void RendererVk::ensureCapsInitialized() const
mNativeCaps.maxRenderbufferSize = mNativeCaps.maxRenderbufferSize =
std::min({limitsVk.maxImageDimension2D, limitsVk.maxFramebufferWidth, std::min({limitsVk.maxImageDimension2D, limitsVk.maxFramebufferWidth,
limitsVk.maxFramebufferHeight}); limitsVk.maxFramebufferHeight});
mNativeCaps.minAliasedPointSize = std::max(1.0f, limitsVk.pointSizeRange[0]); mNativeCaps.minAliasedPointSize = std::max(1.0f, limitsVk.pointSizeRange[0]);
mNativeCaps.maxAliasedPointSize = limitsVk.pointSizeRange[1]; mNativeCaps.maxAliasedPointSize = limitsVk.pointSizeRange[1];
mNativeCaps.minAliasedLineWidth = 1.0f; mNativeCaps.minAliasedLineWidth = 1.0f;
mNativeCaps.maxAliasedLineWidth = 1.0f; mNativeCaps.maxAliasedLineWidth = 1.0f;
...@@ -211,14 +214,14 @@ void RendererVk::ensureCapsInitialized() const ...@@ -211,14 +214,14 @@ void RendererVk::ensureCapsInitialized() const
// Uniforms are implemented using a uniform buffer, so the max number of uniforms we can // Uniforms are implemented using a uniform buffer, so the max number of uniforms we can
// support is the max buffer range divided by the size of a single uniform (4X float). // support is the max buffer range divided by the size of a single uniform (4X float).
mNativeCaps.maxVertexUniformVectors = maxUniformVectors; mNativeCaps.maxVertexUniformVectors = maxUniformVectors;
mNativeCaps.maxFragmentUniformVectors = maxUniformVectors; mNativeCaps.maxFragmentUniformVectors = maxUniformVectors;
mNativeCaps.maxFragmentInputComponents = maxUniformComponents; mNativeCaps.maxFragmentInputComponents = maxUniformComponents;
for (gl::ShaderType shaderType : gl::AllShaderTypes()) for (gl::ShaderType shaderType : gl::AllShaderTypes())
{ {
mNativeCaps.maxShaderUniformComponents[shaderType] = maxUniformComponents; mNativeCaps.maxShaderUniformComponents[shaderType] = maxUniformComponents;
} }
mNativeCaps.maxUniformLocations = maxUniformVectors; mNativeCaps.maxUniformLocations = maxUniformVectors;
// Every stage has 1 reserved uniform buffer for the default uniforms, and 1 for the driver // Every stage has 1 reserved uniform buffer for the default uniforms, and 1 for the driver
// uniforms. // uniforms.
...@@ -235,7 +238,7 @@ void RendererVk::ensureCapsInitialized() const ...@@ -235,7 +238,7 @@ void RendererVk::ensureCapsInitialized() const
{ {
mNativeCaps.maxShaderUniformBlocks[shaderType] = maxPerStageUniformBuffers; mNativeCaps.maxShaderUniformBlocks[shaderType] = maxPerStageUniformBuffers;
} }
mNativeCaps.maxCombinedUniformBlocks = maxCombinedUniformBuffers; mNativeCaps.maxCombinedUniformBlocks = maxCombinedUniformBuffers;
mNativeCaps.maxUniformBufferBindings = maxCombinedUniformBuffers; mNativeCaps.maxUniformBufferBindings = maxCombinedUniformBuffers;
mNativeCaps.maxUniformBlockSize = maxUniformBlockSize; mNativeCaps.maxUniformBlockSize = maxUniformBlockSize;
...@@ -252,7 +255,7 @@ void RendererVk::ensureCapsInitialized() const ...@@ -252,7 +255,7 @@ void RendererVk::ensureCapsInitialized() const
{ {
mNativeCaps.maxShaderTextureImageUnits[shaderType] = maxPerStageTextures; mNativeCaps.maxShaderTextureImageUnits[shaderType] = maxPerStageTextures;
} }
mNativeCaps.maxCombinedTextureImageUnits = maxCombinedTextures; mNativeCaps.maxCombinedTextureImageUnits = maxCombinedTextures;
uint32_t maxPerStageStorageBuffers = limitsVk.maxPerStageDescriptorStorageBuffers; uint32_t maxPerStageStorageBuffers = limitsVk.maxPerStageDescriptorStorageBuffers;
uint32_t maxVertexStageStorageBuffers = maxPerStageStorageBuffers; uint32_t maxVertexStageStorageBuffers = maxPerStageStorageBuffers;
......
...@@ -5101,6 +5101,15 @@ bool ValidateGetRenderbufferParameterivBase(Context *context, ...@@ -5101,6 +5101,15 @@ bool ValidateGetRenderbufferParameterivBase(Context *context,
} }
break; break;
case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
case GL_IMPLEMENTATION_COLOR_READ_TYPE:
if (!context->getExtensions().getImageANGLE)
{
context->validationError(GL_INVALID_ENUM, kGetImageExtensionNotEnabled);
return false;
}
break;
default: default:
context->validationError(GL_INVALID_ENUM, kEnumNotSupported); context->validationError(GL_INVALID_ENUM, kEnumNotSupported);
return false; return false;
...@@ -5311,6 +5320,15 @@ bool ValidateGetTexParameterBase(Context *context, ...@@ -5311,6 +5320,15 @@ bool ValidateGetTexParameterBase(Context *context,
} }
break; break;
case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
case GL_IMPLEMENTATION_COLOR_READ_TYPE:
if (!context->getExtensions().getImageANGLE)
{
context->validationError(GL_INVALID_ENUM, kGetImageExtensionNotEnabled);
return false;
}
break;
default: default:
context->validationError(GL_INVALID_ENUM, kEnumNotSupported); context->validationError(GL_INVALID_ENUM, kEnumNotSupported);
return false; return false;
...@@ -5418,6 +5436,82 @@ bool ValidateGetVertexAttribBase(Context *context, ...@@ -5418,6 +5436,82 @@ bool ValidateGetVertexAttribBase(Context *context,
return true; return true;
} }
bool ValidatePixelPack(Context *context,
GLenum format,
GLenum type,
GLint x,
GLint y,
GLsizei width,
GLsizei height,
GLsizei bufSize,
GLsizei *length,
void *pixels)
{
// Check for pixel pack buffer related API errors
Buffer *pixelPackBuffer = context->getState().getTargetBuffer(BufferBinding::PixelPack);
if (pixelPackBuffer != nullptr && pixelPackBuffer->isMapped())
{
// ...the buffer object's data store is currently mapped.
context->validationError(GL_INVALID_OPERATION, kBufferMapped);
return false;
}
if (context->getExtensions().webglCompatibility && pixelPackBuffer != nullptr &&
pixelPackBuffer->isBoundForTransformFeedbackAndOtherUse())
{
context->validationError(GL_INVALID_OPERATION, kPixelPackBufferBoundForTransformFeedback);
return false;
}
// .. the data would be packed to the buffer object such that the memory writes required
// would exceed the data store size.
const InternalFormat &formatInfo = GetInternalFormatInfo(format, type);
const Extents size(width, height, 1);
const auto &pack = context->getState().getPackState();
GLuint endByte = 0;
if (!formatInfo.computePackUnpackEndByte(type, size, pack, false, &endByte))
{
context->validationError(GL_INVALID_OPERATION, kIntegerOverflow);
return false;
}
if (bufSize >= 0)
{
if (pixelPackBuffer == nullptr && static_cast<size_t>(bufSize) < endByte)
{
context->validationError(GL_INVALID_OPERATION, kInsufficientBufferSize);
return false;
}
}
if (pixelPackBuffer != nullptr)
{
CheckedNumeric<size_t> checkedEndByte(endByte);
CheckedNumeric<size_t> checkedOffset(reinterpret_cast<size_t>(pixels));
checkedEndByte += checkedOffset;
if (checkedEndByte.ValueOrDie() > static_cast<size_t>(pixelPackBuffer->getSize()))
{
// Overflow past the end of the buffer
context->validationError(GL_INVALID_OPERATION, kParamOverflow);
return false;
}
}
if (pixelPackBuffer == nullptr && length != nullptr)
{
if (endByte > static_cast<size_t>(std::numeric_limits<GLsizei>::max()))
{
context->validationError(GL_INVALID_OPERATION, kIntegerOverflow);
return false;
}
*length = static_cast<GLsizei>(endByte);
}
return true;
}
bool ValidateReadPixelsBase(Context *context, bool ValidateReadPixelsBase(Context *context,
GLint x, GLint x,
GLint y, GLint y,
...@@ -5532,67 +5626,10 @@ bool ValidateReadPixelsBase(Context *context, ...@@ -5532,67 +5626,10 @@ bool ValidateReadPixelsBase(Context *context,
return false; return false;
} }
// Check for pixel pack buffer related API errors if (!ValidatePixelPack(context, format, type, x, y, width, height, bufSize, length, pixels))
Buffer *pixelPackBuffer = context->getState().getTargetBuffer(BufferBinding::PixelPack);
if (pixelPackBuffer != nullptr && pixelPackBuffer->isMapped())
{ {
// ...the buffer object's data store is currently mapped.
context->validationError(GL_INVALID_OPERATION, kBufferMapped);
return false; return false;
} }
if (context->getExtensions().webglCompatibility && pixelPackBuffer != nullptr &&
pixelPackBuffer->isBoundForTransformFeedbackAndOtherUse())
{
context->validationError(GL_INVALID_OPERATION, kPixelPackBufferBoundForTransformFeedback);
return false;
}
// .. the data would be packed to the buffer object such that the memory writes required
// would exceed the data store size.
const InternalFormat &formatInfo = GetInternalFormatInfo(format, type);
const Extents size(width, height, 1);
const auto &pack = context->getState().getPackState();
GLuint endByte = 0;
if (!formatInfo.computePackUnpackEndByte(type, size, pack, false, &endByte))
{
context->validationError(GL_INVALID_OPERATION, kIntegerOverflow);
return false;
}
if (bufSize >= 0)
{
if (pixelPackBuffer == nullptr && static_cast<size_t>(bufSize) < endByte)
{
context->validationError(GL_INVALID_OPERATION, kInsufficientBufferSize);
return false;
}
}
if (pixelPackBuffer != nullptr)
{
CheckedNumeric<size_t> checkedEndByte(endByte);
CheckedNumeric<size_t> checkedOffset(reinterpret_cast<size_t>(pixels));
checkedEndByte += checkedOffset;
if (checkedEndByte.ValueOrDie() > static_cast<size_t>(pixelPackBuffer->getSize()))
{
// Overflow past the end of the buffer
context->validationError(GL_INVALID_OPERATION, kParamOverflow);
return false;
}
}
if (pixelPackBuffer == nullptr && length != nullptr)
{
if (endByte > static_cast<size_t>(std::numeric_limits<GLsizei>::max()))
{
context->validationError(GL_INVALID_OPERATION, kIntegerOverflow);
return false;
}
*length = static_cast<GLsizei>(endByte);
}
auto getClippedExtent = [](GLint start, GLsizei length, int bufferSize, GLsizei *outExtent) { auto getClippedExtent = [](GLint start, GLsizei length, int bufferSize, GLsizei *outExtent) {
angle::CheckedNumeric<int> clippedExtent(length); angle::CheckedNumeric<int> clippedExtent(length);
...@@ -5719,6 +5756,7 @@ bool ValidateTexParameterBase(Context *context, ...@@ -5719,6 +5756,7 @@ bool ValidateTexParameterBase(Context *context,
return false; return false;
} }
break; break;
default: default:
break; break;
} }
......
...@@ -126,6 +126,17 @@ bool ValidateBlitFramebufferParameters(Context *context, ...@@ -126,6 +126,17 @@ bool ValidateBlitFramebufferParameters(Context *context,
GLbitfield mask, GLbitfield mask,
GLenum filter); GLenum filter);
bool ValidatePixelPack(Context *context,
GLenum format,
GLenum type,
GLint x,
GLint y,
GLsizei width,
GLsizei height,
GLsizei bufSize,
GLsizei *length,
void *pixels);
bool ValidateReadPixelsBase(Context *context, bool ValidateReadPixelsBase(Context *context,
GLint x, GLint x,
GLint y, GLint y,
......
...@@ -8,9 +8,39 @@ ...@@ -8,9 +8,39 @@
#include "libANGLE/validationESEXT_autogen.h" #include "libANGLE/validationESEXT_autogen.h"
#include "libANGLE/Context.h" #include "libANGLE/Context.h"
#include "libANGLE/ErrorStrings.h"
#include "libANGLE/validationES.h"
namespace gl namespace gl
{ {
using namespace err;
namespace
{
template <typename ObjectT>
bool ValidateGetImageFormatAndType(Context *context, ObjectT *obj, GLenum format, GLenum type)
{
GLenum implFormat = obj->getImplementationColorReadFormat(context);
if (!ValidES3Format(format) && (format != implFormat || format == GL_NONE))
{
context->validationError(GL_INVALID_ENUM, kInvalidFormat);
return false;
}
GLenum implType = obj->getImplementationColorReadType(context);
if (!ValidES3Type(type) && (type != implType || type == GL_NONE))
{
context->validationError(GL_INVALID_ENUM, kInvalidType);
return false;
}
// Format/type combinations are not yet validated.
return true;
}
} // namespace
bool ValidateGetTexImageANGLE(Context *context, bool ValidateGetTexImageANGLE(Context *context,
TextureTarget target, TextureTarget target,
GLint level, GLint level,
...@@ -18,14 +48,81 @@ bool ValidateGetTexImageANGLE(Context *context, ...@@ -18,14 +48,81 @@ bool ValidateGetTexImageANGLE(Context *context,
GLenum type, GLenum type,
void *pixels) void *pixels)
{ {
return false; if (!context->getExtensions().getImageANGLE)
{
context->validationError(GL_INVALID_OPERATION, kGetImageExtensionNotEnabled);
return false;
}
if (!ValidTexture2DDestinationTarget(context, target) &&
!ValidTexture3DDestinationTarget(context, target))
{
context->validationError(GL_INVALID_ENUM, kInvalidTextureTarget);
return false;
}
if (level < 0)
{
context->validationError(GL_INVALID_VALUE, kNegativeLevel);
return false;
}
TextureType textureType = TextureTargetToType(target);
if (!ValidMipLevel(context, textureType, level))
{
context->validationError(GL_INVALID_VALUE, kInvalidMipLevel);
return false;
}
Texture *texture = context->getTextureByTarget(target);
if (!ValidateGetImageFormatAndType(context, texture, format, type))
{
return false;
}
GLsizei width = static_cast<GLsizei>(texture->getWidth(target, level));
GLsizei height = static_cast<GLsizei>(texture->getHeight(target, level));
if (!ValidatePixelPack(context, format, type, 0, 0, width, height, -1, nullptr, pixels))
{
return false;
}
return true;
} }
bool ValidateGetRenderbufferImageANGLE(Context *context, bool ValidateGetRenderbufferImageANGLE(Context *context,
GLenum target, GLenum target,
GLenum format, GLenum format,
GLenum type, GLenum type,
void *pixels) void *pixels)
{ {
return false; if (!context->getExtensions().getImageANGLE)
{
context->validationError(GL_INVALID_OPERATION, kGetImageExtensionNotEnabled);
return false;
}
if (target != GL_RENDERBUFFER)
{
context->validationError(GL_INVALID_ENUM, kInvalidRenderbufferTarget);
return false;
}
Renderbuffer *renderbuffer = context->getState().getCurrentRenderbuffer();
if (!ValidateGetImageFormatAndType(context, renderbuffer, format, type))
{
return false;
}
GLsizei width = renderbuffer->getWidth();
GLsizei height = renderbuffer->getHeight();
if (!ValidatePixelPack(context, format, type, 0, 0, width, height, -1, nullptr, pixels))
{
return false;
}
return true;
} }
} // namespace gl } // namespace gl
...@@ -43,6 +43,7 @@ angle_end2end_tests_sources = [ ...@@ -43,6 +43,7 @@ angle_end2end_tests_sources = [
"gl_tests/FramebufferRenderMipmapTest.cpp", "gl_tests/FramebufferRenderMipmapTest.cpp",
"gl_tests/FramebufferTest.cpp", "gl_tests/FramebufferTest.cpp",
"gl_tests/GeometryShaderTest.cpp", "gl_tests/GeometryShaderTest.cpp",
"gl_tests/GetImageTest.cpp",
"gl_tests/gles1/AlphaFuncTest.cpp", "gl_tests/gles1/AlphaFuncTest.cpp",
"gl_tests/gles1/BasicDrawTest.cpp", "gl_tests/gles1/BasicDrawTest.cpp",
"gl_tests/gles1/ClientActiveTextureTest.cpp", "gl_tests/gles1/ClientActiveTextureTest.cpp",
......
//
// Copyright 2019 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// GetImageTest:
// Tests for the ANGLE_get_image extension.
//
#include "test_utils/ANGLETest.h"
#include "test_utils/gl_raii.h"
using namespace angle;
namespace
{
constexpr uint32_t kSize = 32;
constexpr char kExtensionName[] = "GL_ANGLE_get_image";
class GetImageTest : public ANGLETest
{
public:
GetImageTest()
{
setWindowWidth(kSize);
setWindowHeight(kSize);
setConfigRedBits(8);
setConfigGreenBits(8);
setConfigBlueBits(8);
setConfigAlphaBits(8);
}
};
class GetImageTestNoExtensions : public ANGLETest
{
public:
GetImageTestNoExtensions() { setExtensionsEnabled(false); }
};
GLTexture InitSimpleTexture()
{
std::vector<GLColor> pixelData(kSize * kSize, GLColor::red);
// Create a simple texture.
GLTexture tex;
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
pixelData.data());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
return tex;
}
GLRenderbuffer InitSimpleRenderbuffer()
{
// Create a simple renderbuffer.
GLRenderbuffer renderbuf;
glBindRenderbuffer(GL_RENDERBUFFER, renderbuf);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, kSize, kSize);
return renderbuf;
}
// Test validation for the extension functions.
TEST_P(GetImageTest, NegativeAPI)
{
// Verify the extension is enabled.
ASSERT_TRUE(IsGLExtensionEnabled(kExtensionName));
// Draw once with simple texture.
GLTexture tex = InitSimpleTexture();
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
ASSERT_GL_NO_ERROR();
// Pack pixels tightly.
glPixelStorei(GL_PACK_ALIGNMENT, 1);
// Verify GetTexImage can work with correct parameters.
std::vector<GLColor> buffer(kSize * kSize);
glGetTexImageANGLE(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
EXPECT_GL_NO_ERROR();
// Test invalid texture target.
glGetTexImageANGLE(GL_TEXTURE_CUBE_MAP, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
EXPECT_GL_ERROR(GL_INVALID_ENUM);
// Test invalid texture level.
glGetTexImageANGLE(GL_TEXTURE_2D, -1, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
EXPECT_GL_ERROR(GL_INVALID_VALUE);
glGetTexImageANGLE(GL_TEXTURE_2D, 2000, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
EXPECT_GL_ERROR(GL_INVALID_VALUE);
// Test invalid format and type.
glGetTexImageANGLE(GL_TEXTURE_2D, 0, GL_NONE, GL_UNSIGNED_BYTE, buffer.data());
EXPECT_GL_ERROR(GL_INVALID_ENUM);
glGetTexImageANGLE(GL_TEXTURE_2D, 0, GL_RGBA, GL_NONE, buffer.data());
EXPECT_GL_ERROR(GL_INVALID_ENUM);
// Create a simple renderbuffer.
GLRenderbuffer renderbuf = InitSimpleRenderbuffer();
ASSERT_GL_NO_ERROR();
// Verify GetRenderbufferImage can work with correct parameters.
glGetRenderbufferImageANGLE(GL_RENDERBUFFER, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
EXPECT_GL_NO_ERROR();
// Test invalid renderbuffer target.
glGetRenderbufferImageANGLE(GL_TEXTURE_2D, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
EXPECT_GL_ERROR(GL_INVALID_ENUM);
// Test invalid renderbuffer format/type.
glGetRenderbufferImageANGLE(GL_RENDERBUFFER, GL_NONE, GL_UNSIGNED_BYTE, buffer.data());
EXPECT_GL_ERROR(GL_INVALID_ENUM);
glGetRenderbufferImageANGLE(GL_RENDERBUFFER, GL_RGBA, GL_NONE, buffer.data());
EXPECT_GL_ERROR(GL_INVALID_ENUM);
// Pack buffer tests. Requires ES 3+ or extension.
if (getClientMajorVersion() >= 3 || IsGLExtensionEnabled("GL_NV_pixel_buffer_object"))
{
// Test valid pack buffer.
GLBuffer packBuffer;
glBindBuffer(GL_PIXEL_PACK_BUFFER, packBuffer);
glBufferData(GL_PIXEL_PACK_BUFFER, kSize * kSize * sizeof(GLColor), nullptr,
GL_STATIC_DRAW);
glGetTexImageANGLE(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
glGetRenderbufferImageANGLE(GL_RENDERBUFFER, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
// Test too small pack buffer.
glBufferData(GL_PIXEL_PACK_BUFFER, kSize, nullptr, GL_STATIC_DRAW);
glGetTexImageANGLE(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
glGetRenderbufferImageANGLE(GL_RENDERBUFFER, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
}
}
// Verifies that the extension enums and entry points are invalid when the extension is disabled.
TEST_P(GetImageTestNoExtensions, EntryPointsInactive)
{
// Verify the extension is not enabled.
ASSERT_FALSE(IsGLExtensionEnabled(kExtensionName));
// Draw once with simple texture.
GLTexture tex = InitSimpleTexture();
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
ASSERT_GL_NO_ERROR();
// Query implementation format and type. Should give invalid enum.
GLint param;
glGetTexParameteriv(GL_TEXTURE_2D, GL_IMPLEMENTATION_COLOR_READ_FORMAT, &param);
EXPECT_GL_ERROR(GL_INVALID_ENUM);
glGetTexParameteriv(GL_TEXTURE_2D, GL_IMPLEMENTATION_COLOR_READ_TYPE, &param);
EXPECT_GL_ERROR(GL_INVALID_ENUM);
// Verify calling GetTexImage produces an error.
std::vector<GLColor> buffer(kSize * kSize, 0);
glGetTexImageANGLE(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
// Create a simple renderbuffer.
GLRenderbuffer renderbuf = InitSimpleRenderbuffer();
ASSERT_GL_NO_ERROR();
// Query implementation format and type. Should give invalid enum.
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_IMPLEMENTATION_COLOR_READ_FORMAT, &param);
EXPECT_GL_ERROR(GL_INVALID_ENUM);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_IMPLEMENTATION_COLOR_READ_TYPE, &param);
EXPECT_GL_ERROR(GL_INVALID_ENUM);
// Verify calling GetRenderbufferImage produces an error.
glGetRenderbufferImageANGLE(GL_RENDERBUFFER, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
}
ANGLE_INSTANTIATE_TEST(GetImageTest, ES2_VULKAN(), ES3_VULKAN());
ANGLE_INSTANTIATE_TEST(GetImageTestNoExtensions, ES2_VULKAN(), ES3_VULKAN());
} // namespace
\ No newline at end of file
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