Commit 1e494cae by Brandon Schade Committed by Commit Bot

Vulkan: Add support for EXT_copy_image

Add support for GL_EXT_copy_image which allows image data transfer between image objects. This is implemented by using the vkCmdCopyImage API call. Bug: angleproject:3593 Test: dEQP-GLES31.functional.copy_image.* Change-Id: I30a34a8711b5d2e5834064d7453e03d6ec0df478 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2393955 Commit-Queue: Brandon Schade <b.schade@samsung.com> Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org>
parent 658ede5d
...@@ -1040,6 +1040,7 @@ const ExtensionInfoMap &GetExtensionInfoMap() ...@@ -1040,6 +1040,7 @@ const ExtensionInfoMap &GetExtensionInfoMap()
map["GL_OES_shader_image_atomic"] = enableableExtension(&Extensions::shaderImageAtomicOES); map["GL_OES_shader_image_atomic"] = enableableExtension(&Extensions::shaderImageAtomicOES);
map["GL_NV_robustness_video_memory_purge"] = esOnlyExtension(&Extensions::robustnessVideoMemoryPurgeNV); map["GL_NV_robustness_video_memory_purge"] = esOnlyExtension(&Extensions::robustnessVideoMemoryPurgeNV);
map["GL_ANGLE_get_tex_level_parameter"] = enableableExtension(&Extensions::getTexLevelParameterANGLE); map["GL_ANGLE_get_tex_level_parameter"] = enableableExtension(&Extensions::getTexLevelParameterANGLE);
map["GL_EXT_copy_image"] = enableableExtension(&Extensions::copyImageEXT);
// GLES1 extensions // GLES1 extensions
map["GL_OES_point_size_array"] = enableableExtension(&Extensions::pointSizeArrayOES); map["GL_OES_point_size_array"] = enableableExtension(&Extensions::pointSizeArrayOES);
map["GL_OES_texture_cube_map"] = enableableExtension(&Extensions::textureCubeMapOES); map["GL_OES_texture_cube_map"] = enableableExtension(&Extensions::textureCubeMapOES);
......
...@@ -665,6 +665,9 @@ struct Extensions ...@@ -665,6 +665,9 @@ struct Extensions
// GL_ANGLE_get_tex_level_parameter // GL_ANGLE_get_tex_level_parameter
bool getTexLevelParameterANGLE = false; bool getTexLevelParameterANGLE = false;
// GL_EXT_copy_image
bool copyImageEXT = false;
}; };
// Pointer to a boolean memeber of the Extensions struct // Pointer to a boolean memeber of the Extensions struct
......
...@@ -4122,7 +4122,75 @@ void Context::copyImageSubData(GLuint srcName, ...@@ -4122,7 +4122,75 @@ void Context::copyImageSubData(GLuint srcName,
GLsizei srcHeight, GLsizei srcHeight,
GLsizei srcDepth) GLsizei srcDepth)
{ {
UNIMPLEMENTED(); // if copy region is zero, the copy is a successful no-op
if ((srcWidth == 0) || (srcHeight == 0) || (srcDepth == 0))
{
return;
}
if (srcTarget == GL_RENDERBUFFER)
{
// Source target is a Renderbuffer
Renderbuffer *readBuffer = getRenderbuffer(FromGL<RenderbufferID>(srcName));
if (dstTarget == GL_RENDERBUFFER)
{
// Destination target is a Renderbuffer
Renderbuffer *writeBuffer = getRenderbuffer(FromGL<RenderbufferID>(dstName));
// Copy Renderbuffer to Renderbuffer
ANGLE_CONTEXT_TRY(writeBuffer->copyRenderbufferSubData(
this, readBuffer, srcLevel, srcX, srcY, srcZ, dstLevel, dstX, dstY, dstZ, srcWidth,
srcHeight, srcDepth));
}
else
{
// Destination target is a Texture
ASSERT(dstTarget == GL_TEXTURE_2D || dstTarget == GL_TEXTURE_2D_ARRAY ||
dstTarget == GL_TEXTURE_3D || dstTarget == GL_TEXTURE_CUBE_MAP);
Texture *writeTexture = getTexture(FromGL<TextureID>(dstName));
ANGLE_CONTEXT_TRY(syncTextureForCopy(writeTexture));
// Copy Renderbuffer to Texture
ANGLE_CONTEXT_TRY(writeTexture->copyRenderbufferSubData(
this, readBuffer, srcLevel, srcX, srcY, srcZ, dstLevel, dstX, dstY, dstZ, srcWidth,
srcHeight, srcDepth));
}
}
else
{
// Source target is a Texture
ASSERT(srcTarget == GL_TEXTURE_2D || srcTarget == GL_TEXTURE_2D_ARRAY ||
srcTarget == GL_TEXTURE_3D || srcTarget == GL_TEXTURE_CUBE_MAP);
Texture *readTexture = getTexture(FromGL<TextureID>(srcName));
ANGLE_CONTEXT_TRY(syncTextureForCopy(readTexture));
if (dstTarget == GL_RENDERBUFFER)
{
// Destination target is a Renderbuffer
Renderbuffer *writeBuffer = getRenderbuffer(FromGL<RenderbufferID>(dstName));
// Copy Texture to Renderbuffer
ANGLE_CONTEXT_TRY(writeBuffer->copyTextureSubData(this, readTexture, srcLevel, srcX,
srcY, srcZ, dstLevel, dstX, dstY,
dstZ, srcWidth, srcHeight, srcDepth));
}
else
{
// Destination target is a Texture
ASSERT(dstTarget == GL_TEXTURE_2D || dstTarget == GL_TEXTURE_2D_ARRAY ||
dstTarget == GL_TEXTURE_3D || dstTarget == GL_TEXTURE_CUBE_MAP);
Texture *writeTexture = getTexture(FromGL<TextureID>(dstName));
ANGLE_CONTEXT_TRY(syncTextureForCopy(writeTexture));
// Copy Texture to Texture
ANGLE_CONTEXT_TRY(writeTexture->copyTextureSubData(
this, readTexture, srcLevel, srcX, srcY, srcZ, dstLevel, dstX, dstY, dstZ, srcWidth,
srcHeight, srcDepth));
}
}
} }
void Context::framebufferTexture2D(GLenum target, void Context::framebufferTexture2D(GLenum target,
...@@ -4862,6 +4930,18 @@ angle::Result Context::syncStateForClear() ...@@ -4862,6 +4930,18 @@ angle::Result Context::syncStateForClear()
return syncState(mClearDirtyBits, mClearDirtyObjects, Command::Clear); return syncState(mClearDirtyBits, mClearDirtyObjects, Command::Clear);
} }
angle::Result Context::syncTextureForCopy(Texture *texture)
{
ASSERT(texture);
// Sync texture not active but scheduled for a copy
if (texture->hasAnyDirtyBit())
{
return texture->syncState(this, Command::Other);
}
return angle::Result::Continue;
}
void Context::activeShaderProgram(ProgramPipelineID pipeline, ShaderProgramID program) void Context::activeShaderProgram(ProgramPipelineID pipeline, ShaderProgramID program)
{ {
Program *shaderProgram = getProgramNoResolveLink(program); Program *shaderProgram = getProgramNoResolveLink(program);
......
...@@ -653,6 +653,7 @@ class Context final : public egl::LabeledObject, angle::NonCopyable, public angl ...@@ -653,6 +653,7 @@ class Context final : public egl::LabeledObject, angle::NonCopyable, public angl
angle::Result syncStateForTexImage(); angle::Result syncStateForTexImage();
angle::Result syncStateForBlit(); angle::Result syncStateForBlit();
angle::Result syncStateForClear(); angle::Result syncStateForClear();
angle::Result syncTextureForCopy(Texture *texture);
VertexArray *checkVertexArrayAllocation(VertexArrayID vertexArrayHandle); VertexArray *checkVertexArrayAllocation(VertexArrayID vertexArrayHandle);
TransformFeedback *checkTransformFeedbackAllocation(TransformFeedbackID transformFeedback); TransformFeedback *checkTransformFeedbackAllocation(TransformFeedbackID transformFeedback);
......
...@@ -104,6 +104,7 @@ MSG kEnumRequiresGLES30 = "Enum requires GLES 3.0"; ...@@ -104,6 +104,7 @@ MSG kEnumRequiresGLES30 = "Enum requires GLES 3.0";
MSG kEnumRequiresGLES31 = "Enum requires GLES 3.1"; MSG kEnumRequiresGLES31 = "Enum requires GLES 3.1";
MSG kES1or32Required = "OpenGL ES 1.x or 3.2 Required"; MSG kES1or32Required = "OpenGL ES 1.x or 3.2 Required";
MSG kES31Required = "OpenGL ES 3.1 Required"; MSG kES31Required = "OpenGL ES 3.1 Required";
MSG kES32Required = "OpenGL ES 3.2 Required";
MSG kES3Required = "OpenGL ES 3.0 Required."; MSG kES3Required = "OpenGL ES 3.0 Required.";
MSG kExceedsComputeWorkGroupCountX = "num_groups_x cannot be greater than MAX_COMPUTE_WORK_GROUP_COUNT[0]"; MSG kExceedsComputeWorkGroupCountX = "num_groups_x cannot be greater than MAX_COMPUTE_WORK_GROUP_COUNT[0]";
MSG kExceedsComputeWorkGroupCountY = "num_groups_y cannot be greater than MAX_COMPUTE_WORK_GROUP_COUNT[1]"; MSG kExceedsComputeWorkGroupCountY = "num_groups_y cannot be greater than MAX_COMPUTE_WORK_GROUP_COUNT[1]";
...@@ -150,6 +151,7 @@ MSG kImageSizeTooSmall = "imageSize is too small."; ...@@ -150,6 +151,7 @@ MSG kImageSizeTooSmall = "imageSize is too small.";
MSG kImmutableMemoryObject = "The memory object is immutable."; MSG kImmutableMemoryObject = "The memory object is immutable.";
MSG kImmutableTextureBound = "The value of TEXTURE_IMMUTABLE_FORMAT for the texture currently bound to target on the active texture unit is true."; MSG kImmutableTextureBound = "The value of TEXTURE_IMMUTABLE_FORMAT for the texture currently bound to target on the active texture unit is true.";
MSG kIncompatibleDrawModeAgainstGeometryShader = "Primitive mode is incompatible with the input primitive type of the geometry shader."; MSG kIncompatibleDrawModeAgainstGeometryShader = "Primitive mode is incompatible with the input primitive type of the geometry shader.";
MSG kIncompatibleTextures = "Texture formats are not compatible";
MSG kIndexExceedsActiveUniformBlockCount = "Index exceeds active uniform block count."; MSG kIndexExceedsActiveUniformBlockCount = "Index exceeds active uniform block count.";
MSG kIndexExceedsMaxActiveUniform = "Index must be less than program active uniform count."; MSG kIndexExceedsMaxActiveUniform = "Index must be less than program active uniform count.";
MSG kIndexExceedsMaxActiveUniformBlock = "Index must be less than program active uniform block count."; MSG kIndexExceedsMaxActiveUniformBlock = "Index must be less than program active uniform block count.";
...@@ -191,6 +193,7 @@ MSG kInvalidCombinedImageUnit = "Specified unit must be in [GL_TEXTURE0, GL_TEXT ...@@ -191,6 +193,7 @@ MSG kInvalidCombinedImageUnit = "Specified unit must be in [GL_TEXTURE0, GL_TEXT
MSG kInvalidComponents = "Invalid components."; MSG kInvalidComponents = "Invalid components.";
MSG kInvalidCompressedFormat = "Not a valid compressed texture format."; MSG kInvalidCompressedFormat = "Not a valid compressed texture format.";
MSG kInvalidCompressedImageSize = "Invalid compressed image size."; MSG kInvalidCompressedImageSize = "Invalid compressed image size.";
MSG kInvalidCompressedRegionSize = "Invalid region for compressed texture format.";
MSG kInvalidConstantColor = "CONSTANT_COLOR (or ONE_MINUS_CONSTANT_COLOR) and CONSTANT_ALPHA (or ONE_MINUS_CONSTANT_ALPHA) cannot be used together as source and destination color factors in the blend function."; MSG kInvalidConstantColor = "CONSTANT_COLOR (or ONE_MINUS_CONSTANT_COLOR) and CONSTANT_ALPHA (or ONE_MINUS_CONSTANT_ALPHA) cannot be used together as source and destination color factors in the blend function.";
MSG kInvalidCopyCombination = "Invalid copy texture format combination."; MSG kInvalidCopyCombination = "Invalid copy texture format combination.";
MSG kInvalidCoverageComponents = "components is not one of GL_RGB, GL_RGBA, GL_ALPHA or GL_NONE."; MSG kInvalidCoverageComponents = "components is not one of GL_RGB, GL_RGBA, GL_ALPHA or GL_NONE.";
...@@ -395,6 +398,7 @@ MSG kNonPositiveDrawTextureDimension = "Both width and height argument of drawn ...@@ -395,6 +398,7 @@ MSG kNonPositiveDrawTextureDimension = "Both width and height argument of drawn
MSG kNoProgramBinaryFormats = "No program binary formats supported."; MSG kNoProgramBinaryFormats = "No program binary formats supported.";
MSG kNoReadFramebuffer = "No active read framebuffer."; MSG kNoReadFramebuffer = "No active read framebuffer.";
MSG kNoSampleAlphaToCoveragesLimitation = "Current renderer doesn't support alpha-to-coverage."; MSG kNoSampleAlphaToCoveragesLimitation = "Current renderer doesn't support alpha-to-coverage.";
MSG kNotTextureComplete = "The texture is not complete.";
MSG kNoTransformArray = "No transform array given."; MSG kNoTransformArray = "No transform array given.";
MSG kNoTransformFeedbackOutputVariables = "The active program has specified no output variables to record."; MSG kNoTransformFeedbackOutputVariables = "The active program has specified no output variables to record.";
MSG kNoZeroDivisor = "At least one enabled attribute must have a divisor of zero."; MSG kNoZeroDivisor = "At least one enabled attribute must have a divisor of zero.";
......
...@@ -169,6 +169,48 @@ angle::Result Renderbuffer::setStorageEGLImageTarget(const Context *context, egl ...@@ -169,6 +169,48 @@ angle::Result Renderbuffer::setStorageEGLImageTarget(const Context *context, egl
return angle::Result::Continue; return angle::Result::Continue;
} }
angle::Result Renderbuffer::copyRenderbufferSubData(Context *context,
const gl::Renderbuffer *srcBuffer,
GLint srcLevel,
GLint srcX,
GLint srcY,
GLint srcZ,
GLint dstLevel,
GLint dstX,
GLint dstY,
GLint dstZ,
GLsizei srcWidth,
GLsizei srcHeight,
GLsizei srcDepth)
{
ANGLE_TRY(mImplementation->copyRenderbufferSubData(context, srcBuffer, srcLevel, srcX, srcY,
srcZ, dstLevel, dstX, dstY, dstZ, srcWidth,
srcHeight, srcDepth));
return angle::Result::Continue;
}
angle::Result Renderbuffer::copyTextureSubData(Context *context,
const gl::Texture *srcTexture,
GLint srcLevel,
GLint srcX,
GLint srcY,
GLint srcZ,
GLint dstLevel,
GLint dstX,
GLint dstY,
GLint dstZ,
GLsizei srcWidth,
GLsizei srcHeight,
GLsizei srcDepth)
{
ANGLE_TRY(mImplementation->copyTextureSubData(context, srcTexture, srcLevel, srcX, srcY, srcZ,
dstLevel, dstX, dstY, dstZ, srcWidth, srcHeight,
srcDepth));
return angle::Result::Continue;
}
rx::RenderbufferImpl *Renderbuffer::getImplementation() const rx::RenderbufferImpl *Renderbuffer::getImplementation() const
{ {
ASSERT(mImplementation); ASSERT(mImplementation);
......
...@@ -90,6 +90,34 @@ class Renderbuffer final : public RefCountObject<RenderbufferID>, ...@@ -90,6 +90,34 @@ class Renderbuffer final : public RefCountObject<RenderbufferID>,
MultisamplingMode mode); MultisamplingMode mode);
angle::Result setStorageEGLImageTarget(const Context *context, egl::Image *imageTarget); angle::Result setStorageEGLImageTarget(const Context *context, egl::Image *imageTarget);
angle::Result copyRenderbufferSubData(Context *context,
const gl::Renderbuffer *srcBuffer,
GLint srcLevel,
GLint srcX,
GLint srcY,
GLint srcZ,
GLint dstLevel,
GLint dstX,
GLint dstY,
GLint dstZ,
GLsizei srcWidth,
GLsizei srcHeight,
GLsizei srcDepth);
angle::Result copyTextureSubData(Context *context,
const gl::Texture *srcTexture,
GLint srcLevel,
GLint srcX,
GLint srcY,
GLint srcZ,
GLint dstLevel,
GLint dstX,
GLint dstY,
GLint dstZ,
GLsizei srcWidth,
GLsizei srcHeight,
GLsizei srcDepth);
rx::RenderbufferImpl *getImplementation() const; rx::RenderbufferImpl *getImplementation() const;
GLsizei getWidth() const; GLsizei getWidth() const;
......
...@@ -1326,6 +1326,52 @@ angle::Result Texture::copySubImage(Context *context, ...@@ -1326,6 +1326,52 @@ angle::Result Texture::copySubImage(Context *context,
return angle::Result::Continue; return angle::Result::Continue;
} }
angle::Result Texture::copyRenderbufferSubData(Context *context,
const gl::Renderbuffer *srcBuffer,
GLint srcLevel,
GLint srcX,
GLint srcY,
GLint srcZ,
GLint dstLevel,
GLint dstX,
GLint dstY,
GLint dstZ,
GLsizei srcWidth,
GLsizei srcHeight,
GLsizei srcDepth)
{
ANGLE_TRY(mTexture->copyRenderbufferSubData(context, srcBuffer, srcLevel, srcX, srcY, srcZ,
dstLevel, dstX, dstY, dstZ, srcWidth, srcHeight,
srcDepth));
signalDirtyStorage(InitState::Initialized);
return angle::Result::Continue;
}
angle::Result Texture::copyTextureSubData(Context *context,
const gl::Texture *srcTexture,
GLint srcLevel,
GLint srcX,
GLint srcY,
GLint srcZ,
GLint dstLevel,
GLint dstX,
GLint dstY,
GLint dstZ,
GLsizei srcWidth,
GLsizei srcHeight,
GLsizei srcDepth)
{
ANGLE_TRY(mTexture->copyTextureSubData(context, srcTexture, srcLevel, srcX, srcY, srcZ,
dstLevel, dstX, dstY, dstZ, srcWidth, srcHeight,
srcDepth));
signalDirtyStorage(InitState::Initialized);
return angle::Result::Continue;
}
angle::Result Texture::copyTexture(Context *context, angle::Result Texture::copyTexture(Context *context,
TextureTarget target, TextureTarget target,
GLint level, GLint level,
......
...@@ -390,6 +390,34 @@ class Texture final : public RefCountObject<TextureID>, ...@@ -390,6 +390,34 @@ class Texture final : public RefCountObject<TextureID>,
const Rectangle &sourceArea, const Rectangle &sourceArea,
Framebuffer *source); Framebuffer *source);
angle::Result copyRenderbufferSubData(Context *context,
const gl::Renderbuffer *srcBuffer,
GLint srcLevel,
GLint srcX,
GLint srcY,
GLint srcZ,
GLint dstLevel,
GLint dstX,
GLint dstY,
GLint dstZ,
GLsizei srcWidth,
GLsizei srcHeight,
GLsizei srcDepth);
angle::Result copyTextureSubData(Context *context,
const gl::Texture *srcTexture,
GLint srcLevel,
GLint srcX,
GLint srcY,
GLint srcZ,
GLint dstLevel,
GLint dstX,
GLint dstY,
GLint dstZ,
GLsizei srcWidth,
GLsizei srcHeight,
GLsizei srcDepth);
angle::Result copyTexture(Context *context, angle::Result copyTexture(Context *context,
TextureTarget target, TextureTarget target,
GLint level, GLint level,
......
...@@ -49,6 +49,34 @@ class RenderbufferImpl : public FramebufferAttachmentObjectImpl ...@@ -49,6 +49,34 @@ 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 angle::Result copyRenderbufferSubData(const gl::Context *context,
const gl::Renderbuffer *srcBuffer,
GLint srcLevel,
GLint srcX,
GLint srcY,
GLint srcZ,
GLint dstLevel,
GLint dstX,
GLint dstY,
GLint dstZ,
GLsizei srcWidth,
GLsizei srcHeight,
GLsizei srcDepth);
virtual angle::Result copyTextureSubData(const gl::Context *context,
const gl::Texture *srcTexture,
GLint srcLevel,
GLint srcX,
GLint srcY,
GLint srcZ,
GLint dstLevel,
GLint dstX,
GLint dstY,
GLint dstZ,
GLsizei srcWidth,
GLsizei srcHeight,
GLsizei srcDepth);
virtual GLenum getColorReadFormat(const gl::Context *context); virtual GLenum getColorReadFormat(const gl::Context *context);
virtual GLenum getColorReadType(const gl::Context *context); virtual GLenum getColorReadType(const gl::Context *context);
...@@ -66,6 +94,42 @@ class RenderbufferImpl : public FramebufferAttachmentObjectImpl ...@@ -66,6 +94,42 @@ class RenderbufferImpl : public FramebufferAttachmentObjectImpl
const gl::RenderbufferState &mState; const gl::RenderbufferState &mState;
}; };
inline angle::Result RenderbufferImpl::copyRenderbufferSubData(const gl::Context *context,
const gl::Renderbuffer *srcBuffer,
GLint srcLevel,
GLint srcX,
GLint srcY,
GLint srcZ,
GLint dstLevel,
GLint dstX,
GLint dstY,
GLint dstZ,
GLsizei srcWidth,
GLsizei srcHeight,
GLsizei srcDepth)
{
UNREACHABLE();
return angle::Result::Stop;
}
inline angle::Result RenderbufferImpl::copyTextureSubData(const gl::Context *context,
const gl::Texture *srcTexture,
GLint srcLevel,
GLint srcX,
GLint srcY,
GLint srcZ,
GLint dstLevel,
GLint dstX,
GLint dstY,
GLint dstZ,
GLsizei srcWidth,
GLsizei srcHeight,
GLsizei srcDepth)
{
UNREACHABLE();
return angle::Result::Stop;
}
inline GLint RenderbufferImpl::getMemorySize() const inline GLint RenderbufferImpl::getMemorySize() const
{ {
return 0; return 0;
......
...@@ -44,6 +44,42 @@ angle::Result TextureImpl::copySubTexture(const gl::Context *context, ...@@ -44,6 +44,42 @@ angle::Result TextureImpl::copySubTexture(const gl::Context *context,
return angle::Result::Stop; return angle::Result::Stop;
} }
angle::Result TextureImpl::copyRenderbufferSubData(const gl::Context *context,
const gl::Renderbuffer *srcBuffer,
GLint srcLevel,
GLint srcX,
GLint srcY,
GLint srcZ,
GLint dstLevel,
GLint dstX,
GLint dstY,
GLint dstZ,
GLsizei srcWidth,
GLsizei srcHeight,
GLsizei srcDepth)
{
UNREACHABLE();
return angle::Result::Stop;
}
angle::Result TextureImpl::copyTextureSubData(const gl::Context *context,
const gl::Texture *srcTexture,
GLint srcLevel,
GLint srcX,
GLint srcY,
GLint srcZ,
GLint dstLevel,
GLint dstX,
GLint dstY,
GLint dstZ,
GLsizei srcWidth,
GLsizei srcHeight,
GLsizei srcDepth)
{
UNREACHABLE();
return angle::Result::Stop;
}
angle::Result TextureImpl::copyCompressedTexture(const gl::Context *context, angle::Result TextureImpl::copyCompressedTexture(const gl::Context *context,
const gl::Texture *source) const gl::Texture *source)
{ {
......
...@@ -112,6 +112,34 @@ class TextureImpl : public FramebufferAttachmentObjectImpl ...@@ -112,6 +112,34 @@ class TextureImpl : public FramebufferAttachmentObjectImpl
bool unpackUnmultiplyAlpha, bool unpackUnmultiplyAlpha,
const gl::Texture *source); const gl::Texture *source);
virtual angle::Result copyRenderbufferSubData(const gl::Context *context,
const gl::Renderbuffer *srcBuffer,
GLint srcLevel,
GLint srcX,
GLint srcY,
GLint srcZ,
GLint dstLevel,
GLint dstX,
GLint dstY,
GLint dstZ,
GLsizei srcWidth,
GLsizei srcHeight,
GLsizei srcDepth);
virtual angle::Result copyTextureSubData(const gl::Context *context,
const gl::Texture *srcTexture,
GLint srcLevel,
GLint srcX,
GLint srcY,
GLint srcZ,
GLint dstLevel,
GLint dstX,
GLint dstY,
GLint dstZ,
GLsizei srcWidth,
GLsizei srcHeight,
GLsizei srcDepth);
virtual angle::Result copyCompressedTexture(const gl::Context *context, virtual angle::Result copyCompressedTexture(const gl::Context *context,
const gl::Texture *source); const gl::Texture *source);
......
...@@ -111,6 +111,40 @@ angle::Result TextureNULL::copySubTexture(const gl::Context *context, ...@@ -111,6 +111,40 @@ angle::Result TextureNULL::copySubTexture(const gl::Context *context,
return angle::Result::Continue; return angle::Result::Continue;
} }
angle::Result TextureNULL::copyRenderbufferSubData(const gl::Context *context,
const gl::Renderbuffer *srcBuffer,
GLint srcLevel,
GLint srcX,
GLint srcY,
GLint srcZ,
GLint dstLevel,
GLint dstX,
GLint dstY,
GLint dstZ,
GLsizei srcWidth,
GLsizei srcHeight,
GLsizei srcDepth)
{
return angle::Result::Continue;
}
angle::Result TextureNULL::copyTextureSubData(const gl::Context *context,
const gl::Texture *srcTexture,
GLint srcLevel,
GLint srcX,
GLint srcY,
GLint srcZ,
GLint dstLevel,
GLint dstX,
GLint dstY,
GLint dstZ,
GLsizei srcWidth,
GLsizei srcHeight,
GLsizei srcDepth)
{
return angle::Result::Continue;
}
angle::Result TextureNULL::copyCompressedTexture(const gl::Context *context, angle::Result TextureNULL::copyCompressedTexture(const gl::Context *context,
const gl::Texture *source) const gl::Texture *source)
{ {
......
...@@ -84,6 +84,34 @@ class TextureNULL : public TextureImpl ...@@ -84,6 +84,34 @@ class TextureNULL : public TextureImpl
bool unpackUnmultiplyAlpha, bool unpackUnmultiplyAlpha,
const gl::Texture *source) override; const gl::Texture *source) override;
angle::Result copyRenderbufferSubData(const gl::Context *context,
const gl::Renderbuffer *srcBuffer,
GLint srcLevel,
GLint srcX,
GLint srcY,
GLint srcZ,
GLint dstLevel,
GLint dstX,
GLint dstY,
GLint dstZ,
GLsizei srcWidth,
GLsizei srcHeight,
GLsizei srcDepth) override;
angle::Result copyTextureSubData(const gl::Context *context,
const gl::Texture *srcTexture,
GLint srcLevel,
GLint srcX,
GLint srcY,
GLint srcZ,
GLint dstLevel,
GLint dstX,
GLint dstY,
GLint dstZ,
GLsizei srcWidth,
GLsizei srcHeight,
GLsizei srcDepth) override;
angle::Result copyCompressedTexture(const gl::Context *context, angle::Result copyCompressedTexture(const gl::Context *context,
const gl::Texture *source) override; const gl::Texture *source) override;
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "libANGLE/renderer/vulkan/ContextVk.h" #include "libANGLE/renderer/vulkan/ContextVk.h"
#include "libANGLE/renderer/vulkan/ImageVk.h" #include "libANGLE/renderer/vulkan/ImageVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h" #include "libANGLE/renderer/vulkan/RendererVk.h"
#include "libANGLE/renderer/vulkan/TextureVk.h"
namespace rx namespace rx
{ {
...@@ -190,6 +191,57 @@ angle::Result RenderbufferVk::setStorageEGLImageTarget(const gl::Context *contex ...@@ -190,6 +191,57 @@ angle::Result RenderbufferVk::setStorageEGLImageTarget(const gl::Context *contex
return angle::Result::Continue; return angle::Result::Continue;
} }
angle::Result RenderbufferVk::copyRenderbufferSubData(const gl::Context *context,
const gl::Renderbuffer *srcBuffer,
GLint srcLevel,
GLint srcX,
GLint srcY,
GLint srcZ,
GLint dstLevel,
GLint dstX,
GLint dstY,
GLint dstZ,
GLsizei srcWidth,
GLsizei srcHeight,
GLsizei srcDepth)
{
RenderbufferVk *sourceVk = vk::GetImpl(srcBuffer);
// Make sure the source/destination targets are initialized and all staged updates are flushed.
ANGLE_TRY(sourceVk->ensureImageInitialized(context));
ANGLE_TRY(ensureImageInitialized(context));
return vk::ImageHelper::CopyImageSubData(context, sourceVk->getImage(), srcLevel, srcX, srcY,
srcZ, mImage, dstLevel, dstX, dstY, dstZ, srcWidth,
srcHeight, srcDepth);
}
angle::Result RenderbufferVk::copyTextureSubData(const gl::Context *context,
const gl::Texture *srcTexture,
GLint srcLevel,
GLint srcX,
GLint srcY,
GLint srcZ,
GLint dstLevel,
GLint dstX,
GLint dstY,
GLint dstZ,
GLsizei srcWidth,
GLsizei srcHeight,
GLsizei srcDepth)
{
ContextVk *contextVk = vk::GetImpl(context);
TextureVk *sourceVk = vk::GetImpl(srcTexture);
// Make sure the source/destination targets are initialized and all staged updates are flushed.
ANGLE_TRY(sourceVk->ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
ANGLE_TRY(ensureImageInitialized(context));
return vk::ImageHelper::CopyImageSubData(context, &sourceVk->getImage(), srcLevel, srcX, srcY,
srcZ, mImage, dstLevel, dstX, dstY, dstZ, srcWidth,
srcHeight, srcDepth);
}
angle::Result RenderbufferVk::getAttachmentRenderTarget(const gl::Context *context, angle::Result RenderbufferVk::getAttachmentRenderTarget(const gl::Context *context,
GLenum binding, GLenum binding,
const gl::ImageIndex &imageIndex, const gl::ImageIndex &imageIndex,
...@@ -289,6 +341,14 @@ angle::Result RenderbufferVk::getRenderbufferImage(const gl::Context *context, ...@@ -289,6 +341,14 @@ angle::Result RenderbufferVk::getRenderbufferImage(const gl::Context *context,
format, type, pixels); format, type, pixels);
} }
angle::Result RenderbufferVk::ensureImageInitialized(const gl::Context *context)
{
ANGLE_TRY(setStorage(context, mState.getFormat().info->internalFormat, mState.getWidth(),
mState.getHeight()));
return mImage->flushAllStagedUpdates(vk::GetImpl(context));
}
void RenderbufferVk::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message) void RenderbufferVk::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message)
{ {
ASSERT(index == kRenderbufferImageSubjectIndex && ASSERT(index == kRenderbufferImageSubjectIndex &&
......
...@@ -37,6 +37,34 @@ class RenderbufferVk : public RenderbufferImpl, public angle::ObserverInterface ...@@ -37,6 +37,34 @@ class RenderbufferVk : public RenderbufferImpl, public angle::ObserverInterface
gl::MultisamplingMode mode) override; gl::MultisamplingMode mode) override;
angle::Result setStorageEGLImageTarget(const gl::Context *context, egl::Image *image) override; angle::Result setStorageEGLImageTarget(const gl::Context *context, egl::Image *image) override;
angle::Result copyRenderbufferSubData(const gl::Context *context,
const gl::Renderbuffer *srcBuffer,
GLint srcLevel,
GLint srcX,
GLint srcY,
GLint srcZ,
GLint dstLevel,
GLint dstX,
GLint dstY,
GLint dstZ,
GLsizei srcWidth,
GLsizei srcHeight,
GLsizei srcDepth) override;
angle::Result copyTextureSubData(const gl::Context *context,
const gl::Texture *srcTexture,
GLint srcLevel,
GLint srcX,
GLint srcY,
GLint srcZ,
GLint dstLevel,
GLint dstX,
GLint dstY,
GLint dstZ,
GLsizei srcWidth,
GLsizei srcHeight,
GLsizei srcDepth) override;
angle::Result getAttachmentRenderTarget(const gl::Context *context, angle::Result getAttachmentRenderTarget(const gl::Context *context,
GLenum binding, GLenum binding,
const gl::ImageIndex &imageIndex, const gl::ImageIndex &imageIndex,
...@@ -59,6 +87,8 @@ class RenderbufferVk : public RenderbufferImpl, public angle::ObserverInterface ...@@ -59,6 +87,8 @@ class RenderbufferVk : public RenderbufferImpl, public angle::ObserverInterface
GLenum type, GLenum type,
void *pixels) override; void *pixels) override;
angle::Result ensureImageInitialized(const gl::Context *context);
private: private:
void releaseAndDeleteImage(ContextVk *contextVk); void releaseAndDeleteImage(ContextVk *contextVk);
void releaseImage(ContextVk *contextVk); void releaseImage(ContextVk *contextVk);
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "libANGLE/renderer/vulkan/FramebufferVk.h" #include "libANGLE/renderer/vulkan/FramebufferVk.h"
#include "libANGLE/renderer/vulkan/ImageVk.h" #include "libANGLE/renderer/vulkan/ImageVk.h"
#include "libANGLE/renderer/vulkan/MemoryObjectVk.h" #include "libANGLE/renderer/vulkan/MemoryObjectVk.h"
#include "libANGLE/renderer/vulkan/RenderbufferVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h" #include "libANGLE/renderer/vulkan/RendererVk.h"
#include "libANGLE/renderer/vulkan/SurfaceVk.h" #include "libANGLE/renderer/vulkan/SurfaceVk.h"
#include "libANGLE/renderer/vulkan/vk_format_utils.h" #include "libANGLE/renderer/vulkan/vk_format_utils.h"
...@@ -78,33 +79,18 @@ bool IsTextureLevelDefinitionCompatibleWithImage(const vk::ImageHelper &image, ...@@ -78,33 +79,18 @@ bool IsTextureLevelDefinitionCompatibleWithImage(const vk::ImageHelper &image,
return size == image.getLevelExtents(imageLevelIndexVk) && format == image.getFormat(); return size == image.getLevelExtents(imageLevelIndexVk) && format == image.getFormat();
} }
ANGLE_INLINE bool FormatHasNecessaryFeature(RendererVk *renderer, bool CanCopyWithTransferForCopyTexture(RendererVk *renderer,
VkFormat format, const vk::Format &srcFormat,
VkImageTiling tilingMode, VkImageTiling srcTilingMode,
VkFormatFeatureFlags featureBits) const vk::Format &destFormat,
{ VkImageTiling destTilingMode)
return (tilingMode == VK_IMAGE_TILING_OPTIMAL)
? renderer->hasImageFormatFeatureBits(format, featureBits)
: renderer->hasLinearImageFormatFeatureBits(format, featureBits);
}
bool CanCopyWithTransfer(RendererVk *renderer,
const vk::Format &srcFormat,
VkImageTiling srcTilingMode,
const vk::Format &destFormat,
VkImageTiling destTilingMode)
{ {
// NOTE(syoussefi): technically, you can transfer between formats as long as they have the same // NOTE(syoussefi): technically, you can transfer between formats as long as they have the same
// size and are compatible, but for now, let's just support same-format copies with transfer. // size and are compatible, but for now, let's just support same-format copies with transfer.
bool isFormatCompatible = srcFormat.internalFormat == destFormat.internalFormat; bool isFormatCompatible = srcFormat.internalFormat == destFormat.internalFormat;
bool isTilingCompatible = srcTilingMode == destTilingMode;
bool srcFormatHasNecessaryFeature = FormatHasNecessaryFeature(
renderer, srcFormat.vkImageFormat, srcTilingMode, VK_FORMAT_FEATURE_TRANSFER_SRC_BIT);
bool dstFormatHasNecessaryFeature = FormatHasNecessaryFeature(
renderer, destFormat.vkImageFormat, destTilingMode, VK_FORMAT_FEATURE_TRANSFER_DST_BIT);
return isFormatCompatible && isTilingCompatible && srcFormatHasNecessaryFeature && return isFormatCompatible &&
dstFormatHasNecessaryFeature; vk::CanCopyWithTransfer(renderer, srcFormat, srcTilingMode, destFormat, destTilingMode);
} }
bool CanCopyWithDraw(RendererVk *renderer, bool CanCopyWithDraw(RendererVk *renderer,
...@@ -113,9 +99,10 @@ bool CanCopyWithDraw(RendererVk *renderer, ...@@ -113,9 +99,10 @@ bool CanCopyWithDraw(RendererVk *renderer,
const vk::Format &destFormat, const vk::Format &destFormat,
VkImageTiling destTilingMode) VkImageTiling destTilingMode)
{ {
bool srcFormatHasNecessaryFeature = FormatHasNecessaryFeature( // Checks that the formats in copy by drawing have the appropriate feature bits
bool srcFormatHasNecessaryFeature = vk::FormatHasNecessaryFeature(
renderer, srcFormat.vkImageFormat, srcTilingMode, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT); renderer, srcFormat.vkImageFormat, srcTilingMode, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);
bool dstFormatHasNecessaryFeature = FormatHasNecessaryFeature( bool dstFormatHasNecessaryFeature = vk::FormatHasNecessaryFeature(
renderer, destFormat.vkImageFormat, destTilingMode, VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT); renderer, destFormat.vkImageFormat, destTilingMode, VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT);
return srcFormatHasNecessaryFeature && dstFormatHasNecessaryFeature; return srcFormatHasNecessaryFeature && dstFormatHasNecessaryFeature;
...@@ -528,6 +515,58 @@ angle::Result TextureVk::copySubTexture(const gl::Context *context, ...@@ -528,6 +515,58 @@ angle::Result TextureVk::copySubTexture(const gl::Context *context,
unpackPremultiplyAlpha, unpackUnmultiplyAlpha, vk::GetImpl(source)); unpackPremultiplyAlpha, unpackUnmultiplyAlpha, vk::GetImpl(source));
} }
angle::Result TextureVk::copyRenderbufferSubData(const gl::Context *context,
const gl::Renderbuffer *srcBuffer,
GLint srcLevel,
GLint srcX,
GLint srcY,
GLint srcZ,
GLint dstLevel,
GLint dstX,
GLint dstY,
GLint dstZ,
GLsizei srcWidth,
GLsizei srcHeight,
GLsizei srcDepth)
{
ContextVk *contextVk = vk::GetImpl(context);
RenderbufferVk *sourceVk = vk::GetImpl(srcBuffer);
// Make sure the source/destination targets are initialized and all staged updates are flushed.
ANGLE_TRY(sourceVk->ensureImageInitialized(context));
ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
return vk::ImageHelper::CopyImageSubData(context, sourceVk->getImage(), srcLevel, srcX, srcY,
srcZ, mImage, dstLevel, dstX, dstY, dstZ, srcWidth,
srcHeight, srcDepth);
}
angle::Result TextureVk::copyTextureSubData(const gl::Context *context,
const gl::Texture *srcTexture,
GLint srcLevel,
GLint srcX,
GLint srcY,
GLint srcZ,
GLint dstLevel,
GLint dstX,
GLint dstY,
GLint dstZ,
GLsizei srcWidth,
GLsizei srcHeight,
GLsizei srcDepth)
{
ContextVk *contextVk = vk::GetImpl(context);
TextureVk *sourceVk = vk::GetImpl(srcTexture);
// Make sure the source/destination targets are initialized and all staged updates are flushed.
ANGLE_TRY(sourceVk->ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
return vk::ImageHelper::CopyImageSubData(context, &sourceVk->getImage(), srcLevel, srcX, srcY,
srcZ, mImage, dstLevel, dstX, dstY, dstZ, srcWidth,
srcHeight, srcDepth);
}
angle::Result TextureVk::copyCompressedTexture(const gl::Context *context, angle::Result TextureVk::copyCompressedTexture(const gl::Context *context,
const gl::Texture *source) const gl::Texture *source)
{ {
...@@ -597,8 +636,8 @@ angle::Result TextureVk::copySubImageImpl(const gl::Context *context, ...@@ -597,8 +636,8 @@ angle::Result TextureVk::copySubImageImpl(const gl::Context *context,
clippedSourceArea.width, clippedSourceArea.height, 1); clippedSourceArea.width, clippedSourceArea.height, 1);
// If it's possible to perform the copy with a transfer, that's the best option. // If it's possible to perform the copy with a transfer, that's the best option.
if (!isViewportFlipY && if (!isViewportFlipY && CanCopyWithTransferForCopyTexture(renderer, srcFormat, srcTilingMode,
CanCopyWithTransfer(renderer, srcFormat, srcTilingMode, destFormat, destTilingMode)) destFormat, destTilingMode))
{ {
return copySubImageImplWithTransfer(contextVk, offsetImageIndex, modifiedDestOffset, return copySubImageImplWithTransfer(contextVk, offsetImageIndex, modifiedDestOffset,
destFormat, colorReadRT->getLevelIndex(), destFormat, colorReadRT->getLevelIndex(),
...@@ -673,7 +712,8 @@ angle::Result TextureVk::copySubTextureImpl(ContextVk *contextVk, ...@@ -673,7 +712,8 @@ angle::Result TextureVk::copySubTextureImpl(ContextVk *contextVk,
// If it's possible to perform the copy with a transfer, that's the best option. // If it's possible to perform the copy with a transfer, that's the best option.
if (!unpackFlipY && !unpackPremultiplyAlpha && !unpackUnmultiplyAlpha && if (!unpackFlipY && !unpackPremultiplyAlpha && !unpackUnmultiplyAlpha &&
CanCopyWithTransfer(renderer, sourceVkFormat, srcTilingMode, destVkFormat, destTilingMode)) CanCopyWithTransferForCopyTexture(renderer, sourceVkFormat, srcTilingMode, destVkFormat,
destTilingMode))
{ {
return copySubImageImplWithTransfer(contextVk, offsetImageIndex, destOffset, destVkFormat, return copySubImageImplWithTransfer(contextVk, offsetImageIndex, destOffset, destVkFormat,
sourceLevelGL, sourceBox.z, sourceBox, sourceLevelGL, sourceBox.z, sourceBox,
......
...@@ -100,6 +100,34 @@ class TextureVk : public TextureImpl, public angle::ObserverInterface ...@@ -100,6 +100,34 @@ class TextureVk : public TextureImpl, public angle::ObserverInterface
bool unpackUnmultiplyAlpha, bool unpackUnmultiplyAlpha,
const gl::Texture *source) override; const gl::Texture *source) override;
angle::Result copyRenderbufferSubData(const gl::Context *context,
const gl::Renderbuffer *srcBuffer,
GLint srcLevel,
GLint srcX,
GLint srcY,
GLint srcZ,
GLint dstLevel,
GLint dstX,
GLint dstY,
GLint dstZ,
GLsizei srcWidth,
GLsizei srcHeight,
GLsizei srcDepth) override;
angle::Result copyTextureSubData(const gl::Context *context,
const gl::Texture *srcTexture,
GLint srcLevel,
GLint srcX,
GLint srcY,
GLint srcZ,
GLint dstLevel,
GLint dstX,
GLint dstY,
GLint dstZ,
GLsizei srcWidth,
GLsizei srcHeight,
GLsizei srcDepth) override;
angle::Result copyCompressedTexture(const gl::Context *context, angle::Result copyCompressedTexture(const gl::Context *context,
const gl::Texture *source) override; const gl::Texture *source) override;
......
...@@ -732,6 +732,9 @@ void RendererVk::ensureCapsInitialized() const ...@@ -732,6 +732,9 @@ void RendererVk::ensureCapsInitialized() const
// Enable GL_NV_fence extension. // Enable GL_NV_fence extension.
mNativeExtensions.fenceNV = true; mNativeExtensions.fenceNV = true;
// Enable GL_EXT_copy_image
mNativeExtensions.copyImageEXT = true;
// Geometry shader is optional. // Geometry shader is optional.
if (mPhysicalDeviceFeatures.geometryShader) if (mPhysicalDeviceFeatures.geometryShader)
{ {
......
...@@ -605,6 +605,22 @@ void ExtendRenderPassInvalidateArea(const gl::Rectangle &invalidateArea, gl::Rec ...@@ -605,6 +605,22 @@ void ExtendRenderPassInvalidateArea(const gl::Rectangle &invalidateArea, gl::Rec
gl::ExtendRectangle(*out, invalidateArea, out); gl::ExtendRectangle(*out, invalidateArea, out);
} }
} }
bool CanCopyWithTransferForCopyImage(RendererVk *renderer,
const vk::Format &srcFormat,
VkImageTiling srcTilingMode,
const vk::Format &destFormat,
VkImageTiling destTilingMode)
{
// Transfers for copy image must have the source and destination formats be size compatible
const angle::Format &srcFormatActual = srcFormat.actualImageFormat();
const angle::Format &destFormatActual = destFormat.actualImageFormat();
bool isFormatCompatible = srcFormatActual.pixelBytes == destFormatActual.pixelBytes;
return isFormatCompatible &&
CanCopyWithTransfer(renderer, srcFormat, srcTilingMode, destFormat, destTilingMode);
}
} // anonymous namespace } // anonymous namespace
// This is an arbitrary max. We can change this later if necessary. // This is an arbitrary max. We can change this later if necessary.
...@@ -616,6 +632,32 @@ VkImageLayout ConvertImageLayoutToVkImageLayout(ImageLayout imageLayout) ...@@ -616,6 +632,32 @@ VkImageLayout ConvertImageLayoutToVkImageLayout(ImageLayout imageLayout)
return kImageMemoryBarrierData[imageLayout].layout; return kImageMemoryBarrierData[imageLayout].layout;
} }
bool FormatHasNecessaryFeature(RendererVk *renderer,
VkFormat format,
VkImageTiling tilingMode,
VkFormatFeatureFlags featureBits)
{
return (tilingMode == VK_IMAGE_TILING_OPTIMAL)
? renderer->hasImageFormatFeatureBits(format, featureBits)
: renderer->hasLinearImageFormatFeatureBits(format, featureBits);
}
bool CanCopyWithTransfer(RendererVk *renderer,
const vk::Format &srcFormat,
VkImageTiling srcTilingMode,
const vk::Format &destFormat,
VkImageTiling destTilingMode)
{
// Checks that the formats in the copy transfer have the appropriate tiling and transfer bits
bool isTilingCompatible = srcTilingMode == destTilingMode;
bool srcFormatHasNecessaryFeature = FormatHasNecessaryFeature(
renderer, srcFormat.vkImageFormat, srcTilingMode, VK_FORMAT_FEATURE_TRANSFER_SRC_BIT);
bool dstFormatHasNecessaryFeature = FormatHasNecessaryFeature(
renderer, destFormat.vkImageFormat, destTilingMode, VK_FORMAT_FEATURE_TRANSFER_DST_BIT);
return isTilingCompatible && srcFormatHasNecessaryFeature && dstFormatHasNecessaryFeature;
}
// PackedClearValuesArray implementation // PackedClearValuesArray implementation
PackedClearValuesArray::PackedClearValuesArray() : mValues{} {} PackedClearValuesArray::PackedClearValuesArray() : mValues{} {}
PackedClearValuesArray::~PackedClearValuesArray() = default; PackedClearValuesArray::~PackedClearValuesArray() = default;
...@@ -4184,6 +4226,89 @@ void ImageHelper::Copy(ImageHelper *srcImage, ...@@ -4184,6 +4226,89 @@ void ImageHelper::Copy(ImageHelper *srcImage,
dstImage->getImage(), dstImage->getCurrentLayout(), 1, &region); dstImage->getImage(), dstImage->getCurrentLayout(), 1, &region);
} }
// static
angle::Result ImageHelper::CopyImageSubData(const gl::Context *context,
vk::ImageHelper *srcImage,
GLint srcLevel,
GLint srcX,
GLint srcY,
GLint srcZ,
vk::ImageHelper *dstImage,
GLint dstLevel,
GLint dstX,
GLint dstY,
GLint dstZ,
GLsizei srcWidth,
GLsizei srcHeight,
GLsizei srcDepth)
{
ContextVk *contextVk = vk::GetImpl(context);
const vk::Format &sourceVkFormat = srcImage->getFormat();
VkImageTiling srcTilingMode = srcImage->getTilingMode();
const vk::Format &destVkFormat = dstImage->getFormat();
VkImageTiling destTilingMode = dstImage->getTilingMode();
if (CanCopyWithTransferForCopyImage(contextVk->getRenderer(), sourceVkFormat, srcTilingMode,
destVkFormat, destTilingMode))
{
bool isSrc3D = (srcImage->getType() == VK_IMAGE_TYPE_3D);
bool isDst3D = (dstImage->getType() == VK_IMAGE_TYPE_3D);
const gl::LevelIndex srcLevelGL = gl::LevelIndex(srcLevel);
const gl::LevelIndex dstLevelGL = gl::LevelIndex(dstLevel);
vk::CommandBuffer &commandBuffer = contextVk->getOutsideRenderPassCommandBuffer();
srcImage->retain(&contextVk->getResourceUseList());
dstImage->retain(&contextVk->getResourceUseList());
VkImageCopy region = {};
region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
region.srcSubresource.mipLevel = srcImage->toVkLevel(srcLevelGL).get();
region.srcSubresource.baseArrayLayer = isSrc3D ? 0 : srcZ;
region.srcSubresource.layerCount = isSrc3D ? 1 : srcDepth;
region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
region.dstSubresource.mipLevel = dstImage->toVkLevel(dstLevelGL).get();
region.dstSubresource.baseArrayLayer = isDst3D ? 0 : dstZ;
region.dstSubresource.layerCount = isDst3D ? 1 : srcDepth;
region.srcOffset.x = srcX;
region.srcOffset.y = srcY;
region.srcOffset.z = isSrc3D ? srcZ : 0;
region.dstOffset.x = dstX;
region.dstOffset.y = dstY;
region.dstOffset.z = isDst3D ? dstZ : 0;
region.extent.width = srcWidth;
region.extent.height = srcHeight;
region.extent.depth = (isSrc3D || isDst3D) ? srcDepth : 1;
ANGLE_TRY(contextVk->onImageTransferRead(VK_IMAGE_ASPECT_COLOR_BIT, srcImage));
ANGLE_TRY(contextVk->onImageTransferWrite(
dstLevelGL, 1, region.dstSubresource.baseArrayLayer, region.dstSubresource.layerCount,
VK_IMAGE_ASPECT_COLOR_BIT, dstImage));
ASSERT(commandBuffer.valid() && srcImage->valid() && dstImage->valid());
ASSERT(srcImage->getCurrentLayout() == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
ASSERT(dstImage->getCurrentLayout() == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
commandBuffer.copyImage(srcImage->getImage(), srcImage->getCurrentLayout(),
dstImage->getImage(), dstImage->getCurrentLayout(), 1, &region);
}
else
{
// TODO (anglebug.com/5278) - implement fallback path
// There is a possibility for the underlying source and destination VK image formats to be
// incompatible. An example scenario would be if the source image (RGB8UI) falls back
// to an emulated format(RGBA8UI) but the destination image is natively supported(RGB8I).
UNIMPLEMENTED();
ANGLE_VK_CHECK(contextVk, false, VK_ERROR_FEATURE_NOT_PRESENT);
}
return angle::Result::Continue;
}
angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk, LevelIndex maxLevel) angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk, LevelIndex maxLevel)
{ {
ANGLE_TRY(contextVk->onImageTransferWrite(mBaseLevel + 1, maxLevel.get(), 0, mLayerCount, ANGLE_TRY(contextVk->onImageTransferWrite(mBaseLevel + 1, maxLevel.get(), 0, mLayerCount,
......
...@@ -1234,6 +1234,17 @@ enum class ImageLayout ...@@ -1234,6 +1234,17 @@ enum class ImageLayout
VkImageLayout ConvertImageLayoutToVkImageLayout(ImageLayout imageLayout); VkImageLayout ConvertImageLayoutToVkImageLayout(ImageLayout imageLayout);
bool FormatHasNecessaryFeature(RendererVk *renderer,
VkFormat format,
VkImageTiling tilingMode,
VkFormatFeatureFlags featureBits);
bool CanCopyWithTransfer(RendererVk *renderer,
const vk::Format &srcFormat,
VkImageTiling srcTilingMode,
const vk::Format &destFormat,
VkImageTiling destTilingMode);
class ImageHelper final : public Resource, public angle::Subject class ImageHelper final : public Resource, public angle::Subject
{ {
public: public:
...@@ -1397,6 +1408,21 @@ class ImageHelper final : public Resource, public angle::Subject ...@@ -1397,6 +1408,21 @@ class ImageHelper final : public Resource, public angle::Subject
const VkImageSubresourceLayers &dstSubresources, const VkImageSubresourceLayers &dstSubresources,
CommandBuffer *commandBuffer); CommandBuffer *commandBuffer);
static angle::Result CopyImageSubData(const gl::Context *context,
vk::ImageHelper *srcImage,
GLint srcLevel,
GLint srcX,
GLint srcY,
GLint srcZ,
vk::ImageHelper *dstImage,
GLint dstLevel,
GLint dstX,
GLint dstY,
GLint dstZ,
GLsizei srcWidth,
GLsizei srcHeight,
GLsizei srcDepth);
// Generate mipmap from level 0 into the rest of the levels with blit. // Generate mipmap from level 0 into the rest of the levels with blit.
angle::Result generateMipmapsWithBlit(ContextVk *contextVk, LevelIndex maxLevel); angle::Result generateMipmapsWithBlit(ContextVk *contextVk, LevelIndex maxLevel);
......
...@@ -30,10 +30,11 @@ ...@@ -30,10 +30,11 @@
PROC(Context) \ PROC(Context) \
PROC(Framebuffer) \ PROC(Framebuffer) \
PROC(MemoryObject) \ PROC(MemoryObject) \
PROC(Query) \
PROC(Overlay) \ PROC(Overlay) \
PROC(Program) \ PROC(Program) \
PROC(ProgramPipeline) \ PROC(ProgramPipeline) \
PROC(Query) \
PROC(Renderbuffer) \
PROC(Sampler) \ PROC(Sampler) \
PROC(Semaphore) \ PROC(Semaphore) \
PROC(Texture) \ PROC(Texture) \
...@@ -71,6 +72,7 @@ namespace rx ...@@ -71,6 +72,7 @@ namespace rx
class DisplayVk; class DisplayVk;
class ImageVk; class ImageVk;
class ProgramExecutableVk; class ProgramExecutableVk;
class RenderbufferVk;
class RenderTargetVk; class RenderTargetVk;
class RendererVk; class RendererVk;
class RenderPassCache; class RenderPassCache;
......
...@@ -311,6 +311,23 @@ bool ValidateRobustStateQuery(const Context *context, ...@@ -311,6 +311,23 @@ bool ValidateRobustStateQuery(const Context *context,
GLenum *nativeType, GLenum *nativeType,
unsigned int *numParams); unsigned int *numParams);
bool ValidateCopyImageSubDataBase(const Context *context,
GLuint srcName,
GLenum srcTarget,
GLint srcLevel,
GLint srcX,
GLint srcY,
GLint srcZ,
GLuint dstName,
GLenum dstTarget,
GLint dstLevel,
GLint dstX,
GLint dstY,
GLint dstZ,
GLsizei srcWidth,
GLsizei srcHeight,
GLsizei srcDepth);
bool ValidateCopyTexImageParametersBase(const Context *context, bool ValidateCopyTexImageParametersBase(const Context *context,
TextureTarget target, TextureTarget target,
GLint level, GLint level,
......
...@@ -139,7 +139,15 @@ bool ValidateCopyImageSubData(const Context *context, ...@@ -139,7 +139,15 @@ bool ValidateCopyImageSubData(const Context *context,
GLsizei srcHeight, GLsizei srcHeight,
GLsizei srcDepth) GLsizei srcDepth)
{ {
return true; if (context->getClientVersion() < ES_3_2)
{
context->validationError(GL_INVALID_OPERATION, kES32Required);
return false;
}
return ValidateCopyImageSubDataBase(context, srcName, srcTarget, srcLevel, srcX, srcY, srcZ,
dstName, dstTarget, dstLevel, dstX, dstY, dstZ, srcWidth,
srcHeight, srcDepth);
} }
bool ValidateDebugMessageCallback(const Context *context, bool ValidateDebugMessageCallback(const Context *context,
......
...@@ -568,8 +568,15 @@ bool ValidateCopyImageSubDataEXT(const Context *context, ...@@ -568,8 +568,15 @@ bool ValidateCopyImageSubDataEXT(const Context *context,
GLsizei srcHeight, GLsizei srcHeight,
GLsizei srcDepth) GLsizei srcDepth)
{ {
UNIMPLEMENTED(); if (!context->getExtensions().copyImageEXT)
return false; {
context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled);
return false;
}
return ValidateCopyImageSubDataBase(context, srcName, srcTarget, srcLevel, srcX, srcY, srcZ,
dstName, dstTarget, dstLevel, dstX, dstY, dstZ, srcWidth,
srcHeight, srcDepth);
} }
bool ValidateCopyImageSubDataOES(const Context *context, bool ValidateCopyImageSubDataOES(const Context *context,
...@@ -589,8 +596,15 @@ bool ValidateCopyImageSubDataOES(const Context *context, ...@@ -589,8 +596,15 @@ bool ValidateCopyImageSubDataOES(const Context *context,
GLsizei srcHeight, GLsizei srcHeight,
GLsizei srcDepth) GLsizei srcDepth)
{ {
UNIMPLEMENTED(); if (!context->getExtensions().copyImageEXT)
return false; {
context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled);
return false;
}
return ValidateCopyImageSubDataBase(context, srcName, srcTarget, srcLevel, srcX, srcY, srcZ,
dstName, dstTarget, dstLevel, dstX, dstY, dstZ, srcWidth,
srcHeight, srcDepth);
} }
bool ValidateBufferStorageMemEXT(const Context *context, bool ValidateBufferStorageMemEXT(const Context *context,
......
...@@ -273,3 +273,30 @@ ...@@ -273,3 +273,30 @@
4822 VULKAN ANDROID : dEQP-GLES31.functional.draw_buffers_indexed.random.max_required_draw_buffers.10 = SKIP 4822 VULKAN ANDROID : dEQP-GLES31.functional.draw_buffers_indexed.random.max_required_draw_buffers.10 = SKIP
4822 VULKAN ANDROID : dEQP-GLES31.functional.draw_buffers_indexed.random.max_required_draw_buffers.11 = SKIP 4822 VULKAN ANDROID : dEQP-GLES31.functional.draw_buffers_indexed.random.max_required_draw_buffers.11 = SKIP
4822 VULKAN ANDROID : dEQP-GLES31.functional.draw_buffers_indexed.random.max_required_draw_buffers.17 = SKIP 4822 VULKAN ANDROID : dEQP-GLES31.functional.draw_buffers_indexed.random.max_required_draw_buffers.17 = SKIP
// There is an issue with renderbuffers where the test fails verification before the copy.
3593 VULKAN : dEQP-GLES31.functional.copy_image.non_compressed*renderbuffer* = FAIL
3593 SWIFTSHADER : dEQP-GLES31.functional.copy_image.mixed*renderbuffer* = FAIL
3593 VULKAN ANDROID : dEQP-GLES31.functional.copy_image.mixed*renderbuffer* = FAIL
// Swiftshader fails to create a correct source/destination srgb8_alpha8_astc image before copy, however 5x4 is correct
5275 SWIFTSHADER : dEQP-GLES31.functional.copy_image.*rgba*srgb8_alpha8_astc_*_khr.*_to_texture2d* = FAIL
5275 SWIFTSHADER : dEQP-GLES31.functional.copy_image.*rgba*srgb8_alpha8_astc_*_khr.*_to_cubemap* = FAIL
5275 SWIFTSHADER : dEQP-GLES31.functional.copy_image.*srgb8_alpha8_astc_*_khr_rgba*.*cubemap_to* = FAIL
5275 SWIFTSHADER : dEQP-GLES31.functional.copy_image.*srgb8_alpha8_astc_*_khr_rgba*.*texture2d*_to* = FAIL
5275 SWIFTSHADER : dEQP-GLES31.functional.copy_image.*srgb8_alpha8_astc_5x4_khr.*texture2d*_to_texture2d* = PASS
5275 SWIFTSHADER : dEQP-GLES31.functional.copy_image.*srgb8_alpha8_astc_5x4_khr.*texture2d*_to_cubemap = PASS
5275 SWIFTSHADER : dEQP-GLES31.functional.copy_image.*srgb8_alpha8_astc_5x4_khr.*cubemap*_to_texture2d* = PASS
5275 SWIFTSHADER : dEQP-GLES31.functional.copy_image.*srgb8_alpha8_astc_5x4_khr.*cubemap_to_cubemap = PASS
// Desktop cards without native etc support, angle emulated format fails
5276 AMD VULKAN : dEQP-GLES31.functional.copy_image.compressed.viewclass_eac* = FAIL
5276 AMD VULKAN : dEQP-GLES31.functional.copy_image.compressed.viewclass_etc* = FAIL
5276 AMD VULKAN : dEQP-GLES31.functional.copy_image.mixed.*eac* = FAIL
5276 NVIDIA VULKAN : dEQP-GLES31.functional.copy_image.compressed.viewclass_eac* = FAIL
5276 NVIDIA VULKAN : dEQP-GLES31.functional.copy_image.compressed.viewclass_etc* = FAIL
5276 NVIDIA VULKAN : dEQP-GLES31.functional.copy_image.mixed.*eac* = FAIL
// Vulkan Android failures with these formats
5277 VULKAN ANDROID : dEQP-GLES31.functional.copy_image.non_compressed.viewclass_32_bits.rgba8_snorm_rgb10_a2* = FAIL
5277 VULKAN ANDROID : dEQP-GLES31.functional.copy_image.non_compressed.viewclass_32_bits.rgba8_snorm_rgb9_e5* = FAIL
...@@ -3604,6 +3604,212 @@ TEST_P(Texture2DTestES3, DrawWithBaseLevel1) ...@@ -3604,6 +3604,212 @@ TEST_P(Texture2DTestES3, DrawWithBaseLevel1)
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
} }
// Test basic GL_EXT_copy_image copy without any bound textures
TEST_P(Texture2DTestES3, CopyImage)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_copy_image"));
std::vector<GLColor> texDataRed(4u * 4u, GLColor::red);
GLTexture srcTexture;
GLTexture destTexture;
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, destTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, texDataRed.data());
std::vector<GLColor> texDataGreen(4u * 4u, GLColor::green);
glBindTexture(GL_TEXTURE_2D, srcTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE,
texDataGreen.data());
glBindTexture(GL_TEXTURE_2D, 0);
// copy
glCopyImageSubDataEXT(srcTexture, GL_TEXTURE_2D, 0, 2, 2, 0, destTexture, GL_TEXTURE_2D, 0, 2,
2, 0, 2, 2, 1);
glBindTexture(GL_TEXTURE_2D, destTexture);
EXPECT_GL_NO_ERROR();
glViewport(0, 0, 4, 4);
drawQuad(mProgram, "position", 0.5f);
EXPECT_GL_NO_ERROR();
EXPECT_PIXEL_RECT_EQ(2, 2, 2, 2, GLColor::green);
EXPECT_PIXEL_RECT_EQ(0, 0, 4, 2, GLColor::red);
EXPECT_PIXEL_RECT_EQ(0, 0, 2, 4, GLColor::red);
}
// Test GL_EXT_copy_image copy with a non-zero base level
TEST_P(Texture2DTestES3, CopyImageBaseLevel1)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_copy_image"));
std::vector<GLColor> texDataBlack(8u * 8u, GLColor::black);
std::vector<GLColor> texDataRed(4u * 4u, GLColor::red);
std::vector<GLColor> texDataGreen(4u * 4u, GLColor::green);
std::vector<GLColor> texDataBlue(4u * 4u, GLColor::blue);
GLTexture srcTexture;
GLTexture destTexture;
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, destTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE,
texDataBlack.data());
glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, texDataRed.data());
glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
texDataGreen.data());
glTexImage2D(GL_TEXTURE_2D, 3, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, texDataBlue.data());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
glBindTexture(GL_TEXTURE_2D, srcTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE,
texDataBlack.data());
glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE,
texDataGreen.data());
glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, texDataBlue.data());
glTexImage2D(GL_TEXTURE_2D, 3, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, texDataRed.data());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
glBindTexture(GL_TEXTURE_2D, 0);
// copy
glCopyImageSubDataEXT(srcTexture, GL_TEXTURE_2D, 1, 2, 2, 0, destTexture, GL_TEXTURE_2D, 1, 2,
2, 0, 2, 2, 1);
glBindTexture(GL_TEXTURE_2D, destTexture);
EXPECT_GL_NO_ERROR();
glViewport(0, 0, 4, 4);
drawQuad(mProgram, "position", 0.5f);
EXPECT_GL_NO_ERROR();
EXPECT_PIXEL_RECT_EQ(2, 2, 2, 2, GLColor::green);
EXPECT_PIXEL_RECT_EQ(0, 0, 4, 2, GLColor::red);
EXPECT_PIXEL_RECT_EQ(0, 0, 2, 4, GLColor::red);
}
// Test basic GL_EXT_copy_image copy without any draw calls by attaching the texture
// to a framebuffer and reads from the framebuffer to validate the copy
TEST_P(Texture2DTestES3, CopyImageFB)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_copy_image"));
glViewport(0, 0, 4, 4);
std::vector<GLColor> texDataRed(4u * 4u, GLColor::red);
GLTexture srcTexture;
GLTexture destTexture;
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, destTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, texDataRed.data());
std::vector<GLColor> texDataGreen(4u * 4u, GLColor::green);
glBindTexture(GL_TEXTURE_2D, srcTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE,
texDataGreen.data());
glBindTexture(GL_TEXTURE_2D, 0);
// copy
glCopyImageSubDataEXT(srcTexture, GL_TEXTURE_2D, 0, 0, 0, 0, destTexture, GL_TEXTURE_2D, 0, 0,
1, 0, 3, 3, 1);
EXPECT_GL_NO_ERROR();
GLFramebuffer fb;
glBindFramebuffer(GL_FRAMEBUFFER, fb);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, destTexture, 0);
EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
EXPECT_PIXEL_RECT_EQ(0, 1, 3, 3, GLColor::green);
EXPECT_PIXEL_RECT_EQ(3, 0, 1, 4, GLColor::red);
EXPECT_PIXEL_RECT_EQ(0, 0, 4, 1, GLColor::red);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
// Test GL_EXT_copy_image copy to a framebuffer attachment after
// invalidation. Then draw with blending onto the framebuffer.
TEST_P(Texture2DTestES3, CopyImageFBInvalidateThenBlend)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_copy_image"));
ANGLE_GL_PROGRAM(drawBlueProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Blue());
ANGLE_GL_PROGRAM(drawRedProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
glViewport(0, 0, 4, 4);
GLTexture srcTexture;
GLTexture textureAttachment;
std::vector<GLColor> texDataGreen(4u * 4u, GLColor::green);
glBindTexture(GL_TEXTURE_2D, srcTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE,
texDataGreen.data());
glBindTexture(GL_TEXTURE_2D, 0);
glBindTexture(GL_TEXTURE_2D, textureAttachment);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
glBindTexture(GL_TEXTURE_2D, 0);
GLFramebuffer fb;
glBindFramebuffer(GL_FRAMEBUFFER, fb);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureAttachment,
0);
EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
// Draw something in the texture to make sure it's image is defined.
drawQuad(drawRedProgram, essl1_shaders::PositionAttrib(), 0.0f);
// Invalidate the framebuffer.
const GLenum discards[] = {GL_COLOR_ATTACHMENT0};
glInvalidateFramebuffer(GL_FRAMEBUFFER, 1, discards);
ASSERT_GL_NO_ERROR();
// Copy into the framebuffer attachment.
glCopyImageSubDataEXT(srcTexture, GL_TEXTURE_2D, 0, 0, 0, 0, textureAttachment, GL_TEXTURE_2D,
0, 0, 0, 0, 4, 4, 1);
EXPECT_GL_NO_ERROR();
// Draw and blend, making sure both the copy and draw happen correctly.
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
drawQuad(drawBlueProgram, essl1_shaders::PositionAttrib(), 0.0f);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_RECT_EQ(0, 0, 4, 4, GLColor::cyan);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
// Test that drawing works correctly when levels outside the BASE_LEVEL/MAX_LEVEL range do not // Test that drawing works correctly when levels outside the BASE_LEVEL/MAX_LEVEL range do not
// have images defined. // have images defined.
TEST_P(Texture2DTestES3, DrawWithLevelsOutsideRangeUndefined) TEST_P(Texture2DTestES3, DrawWithLevelsOutsideRangeUndefined)
......
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