Skip to content

Commit bb35bb4

Browse files
null77Commit Bot
authored andcommitted
Vulkan: Implement simple case ANGLE_get_image.
A couple cases are left unimplemented: Incomplete/unused Textures. This leads to a slightly more tricky implementation. Since we need to read back from the staging buffer we will need to flush the Image contents to a temporary buffer. Depth/stencil readback. Requires a more complex pixel packing step. 3D/Cube/2D Array readback. Also requires a more complex packing step. Bug: angleproject:3944 Change-Id: Ic5d9a606177ba7e3e5ab945feb5f555afa11741f Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1879964 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: Cody Northrop <cnorthrop@google.com>
1 parent ec5c3d5 commit bb35bb4

File tree

8 files changed

+204
-32
lines changed

8 files changed

+204
-32
lines changed

src/libANGLE/renderer/vulkan/FramebufferVk.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -458,10 +458,14 @@ angle::Result FramebufferVk::readPixels(const gl::Context *context,
458458
return angle::Result::Continue;
459459
}
460460

461+
const gl::State &glState = contextVk->getState();
462+
gl::Buffer *packBuffer = glState.getTargetBuffer(gl::BufferBinding::PixelPack);
463+
461464
GLuint outputSkipBytes = 0;
462465
PackPixelsParams params;
463-
ANGLE_TRY(vk::ImageHelper::GetReadPixelsParams(contextVk, format, type, area, clippedArea,
464-
&params, &outputSkipBytes));
466+
ANGLE_TRY(vk::ImageHelper::GetReadPixelsParams(contextVk, glState.getPackState(), packBuffer,
467+
format, type, area, clippedArea, &params,
468+
&outputSkipBytes));
465469

466470
if (contextVk->isViewportFlipEnabledForReadFBO())
467471
{

src/libANGLE/renderer/vulkan/RenderbufferVk.cpp

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -225,16 +225,22 @@ void RenderbufferVk::releaseImage(ContextVk *contextVk)
225225
mImageViews.release(renderer);
226226
}
227227

228+
const gl::InternalFormat &RenderbufferVk::getImplementationSizedFormat() const
229+
{
230+
GLenum internalFormat = mImage->getFormat().actualImageFormat().glInternalFormat;
231+
return gl::GetSizedInternalFormatInfo(internalFormat);
232+
}
233+
228234
GLenum RenderbufferVk::getColorReadFormat(const gl::Context *context)
229235
{
230-
UNIMPLEMENTED();
231-
return GL_NONE;
236+
const gl::InternalFormat &sizedFormat = getImplementationSizedFormat();
237+
return sizedFormat.format;
232238
}
233239

234240
GLenum RenderbufferVk::getColorReadType(const gl::Context *context)
235241
{
236-
UNIMPLEMENTED();
237-
return GL_NONE;
242+
const gl::InternalFormat &sizedFormat = getImplementationSizedFormat();
243+
return sizedFormat.type;
238244
}
239245

240246
angle::Result RenderbufferVk::getRenderbufferImage(const gl::Context *context,
@@ -244,7 +250,13 @@ angle::Result RenderbufferVk::getRenderbufferImage(const gl::Context *context,
244250
GLenum type,
245251
void *pixels)
246252
{
247-
UNIMPLEMENTED();
248-
return angle::Result::Continue;
253+
// Storage not defined.
254+
if (!mImage || !mImage->valid())
255+
return angle::Result::Continue;
256+
257+
ContextVk *contextVk = vk::GetImpl(context);
258+
ANGLE_TRY(mImage->flushAllStagedUpdates(contextVk));
259+
return mImage->readPixelsForGetImage(contextVk, packState, packBuffer, 0, 0, format, type,
260+
pixels);
249261
}
250262
} // namespace rx

src/libANGLE/renderer/vulkan/RenderbufferVk.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ class RenderbufferVk : public RenderbufferImpl
6868
size_t width,
6969
size_t height);
7070

71+
const gl::InternalFormat &getImplementationSizedFormat() const;
72+
7173
bool mOwnsImage;
7274
vk::ImageHelper *mImage;
7375
vk::ImageViewHelper mImageViews;

src/libANGLE/renderer/vulkan/TextureVk.cpp

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1269,9 +1269,7 @@ angle::Result TextureVk::ensureImageInitialized(ContextVk *contextVk, ImageMipLe
12691269
const gl::ImageDesc &baseLevelDesc = mState.getBaseLevelDesc();
12701270
const gl::Extents &baseLevelExtents = baseLevelDesc.size;
12711271
const uint32_t levelCount = getMipLevelCount(mipLevels);
1272-
const vk::Format &format =
1273-
contextVk->getRenderer()->getFormat(baseLevelDesc.format.info->sizedInternalFormat);
1274-
1272+
const vk::Format &format = getBaseLevelFormat(contextVk->getRenderer());
12751273
return ensureImageInitializedImpl(contextVk, baseLevelExtents, levelCount, format);
12761274
}
12771275

@@ -1704,16 +1702,34 @@ angle::Result TextureVk::generateMipmapLevelsWithCPU(ContextVk *contextVk,
17041702
return angle::Result::Continue;
17051703
}
17061704

1705+
const gl::InternalFormat &TextureVk::getImplementationSizedFormat(const gl::Context *context) const
1706+
{
1707+
GLenum sizedFormat = GL_NONE;
1708+
1709+
if (mImage && mImage->valid())
1710+
{
1711+
sizedFormat = mImage->getFormat().actualImageFormat().glInternalFormat;
1712+
}
1713+
else
1714+
{
1715+
ContextVk *contextVk = vk::GetImpl(context);
1716+
const vk::Format &format = getBaseLevelFormat(contextVk->getRenderer());
1717+
sizedFormat = format.actualImageFormat().glInternalFormat;
1718+
}
1719+
1720+
return gl::GetSizedInternalFormatInfo(sizedFormat);
1721+
}
1722+
17071723
GLenum TextureVk::getColorReadFormat(const gl::Context *context)
17081724
{
1709-
UNIMPLEMENTED();
1710-
return GL_NONE;
1725+
const gl::InternalFormat &sizedFormat = getImplementationSizedFormat(context);
1726+
return sizedFormat.format;
17111727
}
17121728

17131729
GLenum TextureVk::getColorReadType(const gl::Context *context)
17141730
{
1715-
UNIMPLEMENTED();
1716-
return GL_NONE;
1731+
const gl::InternalFormat &sizedFormat = getImplementationSizedFormat(context);
1732+
return sizedFormat.type;
17171733
}
17181734

17191735
angle::Result TextureVk::getTexImage(const gl::Context *context,
@@ -1725,7 +1741,26 @@ angle::Result TextureVk::getTexImage(const gl::Context *context,
17251741
GLenum type,
17261742
void *pixels)
17271743
{
1744+
ContextVk *contextVk = vk::GetImpl(context);
1745+
if (mImage && mImage->valid())
1746+
{
1747+
ANGLE_TRY(mImage->flushAllStagedUpdates(contextVk));
1748+
1749+
size_t layer =
1750+
gl::IsCubeMapFaceTarget(target) ? gl::CubeMapTextureTargetToFaceIndex(target) : 0;
1751+
return mImage->readPixelsForGetImage(contextVk, packState, packBuffer, level,
1752+
static_cast<uint32_t>(layer), format, type, pixels);
1753+
}
1754+
1755+
// Incomplete or unused texture. Will require a staging texture.
1756+
// TODO(http://anglebug.com/4058): Incomplete texture readback.
17281757
UNIMPLEMENTED();
17291758
return angle::Result::Continue;
17301759
}
1760+
1761+
const vk::Format &TextureVk::getBaseLevelFormat(RendererVk *renderer) const
1762+
{
1763+
const gl::ImageDesc &baseLevelDesc = mState.getBaseLevelDesc();
1764+
return renderer->getFormat(baseLevelDesc.format.info->sizedInternalFormat);
1765+
}
17311766
} // namespace rx

src/libANGLE/renderer/vulkan/TextureVk.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,8 @@ class TextureVk : public TextureImpl
342342
void onStagingBufferChange() { onStateChange(angle::SubjectMessage::SubjectChanged); }
343343

344344
angle::Result changeLevels(ContextVk *contextVk, GLuint baseLevel, GLuint maxLevel);
345+
const gl::InternalFormat &getImplementationSizedFormat(const gl::Context *context) const;
346+
const vk::Format &getBaseLevelFormat(RendererVk *renderer) const;
345347

346348
bool mOwnsImage;
347349

src/libANGLE/renderer/vulkan/vk_helpers.cpp

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2958,16 +2958,15 @@ angle::Result ImageHelper::copyImageDataToBuffer(ContextVk *contextVk,
29582958

29592959
// static
29602960
angle::Result ImageHelper::GetReadPixelsParams(ContextVk *contextVk,
2961+
const gl::PixelPackState &packState,
2962+
gl::Buffer *packBuffer,
29612963
GLenum format,
29622964
GLenum type,
29632965
const gl::Rectangle &area,
29642966
const gl::Rectangle &clippedArea,
29652967
PackPixelsParams *paramsOut,
29662968
GLuint *skipBytesOut)
29672969
{
2968-
const gl::State &glState = contextVk->getState();
2969-
const gl::PixelPackState &packState = glState.getPackState();
2970-
29712970
const gl::InternalFormat &sizedFormatInfo = gl::GetInternalFormatInfo(format, type);
29722971

29732972
GLuint outputPitch = 0;
@@ -2983,10 +2982,48 @@ angle::Result ImageHelper::GetReadPixelsParams(ContextVk *contextVk,
29832982
const angle::Format &angleFormat = GetFormatFromFormatType(format, type);
29842983

29852984
*paramsOut = PackPixelsParams(clippedArea, angleFormat, outputPitch, packState.reverseRowOrder,
2986-
glState.getTargetBuffer(gl::BufferBinding::PixelPack), 0);
2985+
packBuffer, 0);
29872986
return angle::Result::Continue;
29882987
}
29892988

2989+
angle::Result ImageHelper::readPixelsForGetImage(ContextVk *contextVk,
2990+
const gl::PixelPackState &packState,
2991+
gl::Buffer *packBuffer,
2992+
uint32_t level,
2993+
uint32_t layer,
2994+
GLenum format,
2995+
GLenum type,
2996+
void *pixels)
2997+
{
2998+
const angle::Format &angleFormat = GetFormatFromFormatType(format, type);
2999+
3000+
// Depth/stencil readback is not yet implemented.
3001+
// TODO(http://anglebug.com/4058): Depth/stencil readback.
3002+
if (angleFormat.depthBits > 0 || angleFormat.stencilBits > 0)
3003+
{
3004+
UNIMPLEMENTED();
3005+
return angle::Result::Continue;
3006+
}
3007+
3008+
PackPixelsParams params;
3009+
GLuint outputSkipBytes = 0;
3010+
3011+
uint32_t width = std::max(1u, mExtents.width >> level);
3012+
uint32_t height = std::max(1u, mExtents.height >> level);
3013+
gl::Rectangle area(0, 0, width, height);
3014+
3015+
ANGLE_TRY(GetReadPixelsParams(contextVk, packState, packBuffer, format, type, area, area,
3016+
&params, &outputSkipBytes));
3017+
3018+
// Use a temporary staging buffer. Could be optimized.
3019+
vk::RendererScoped<vk::DynamicBuffer> stagingBuffer(contextVk->getRenderer());
3020+
stagingBuffer.get().init(contextVk->getRenderer(), VK_BUFFER_USAGE_TRANSFER_DST_BIT, 1,
3021+
kStagingBufferSize, true);
3022+
3023+
return readPixels(contextVk, area, params, VK_IMAGE_ASPECT_COLOR_BIT, level, 0,
3024+
static_cast<uint8_t *>(pixels) + outputSkipBytes, &stagingBuffer.get());
3025+
}
3026+
29903027
angle::Result ImageHelper::readPixels(ContextVk *contextVk,
29913028
const gl::Rectangle &area,
29923029
const PackPixelsParams &packPixelsParams,
@@ -3101,12 +3138,10 @@ angle::Result ImageHelper::readPixels(ContextVk *contextVk,
31013138
// created with the host coherent bit.
31023139
ANGLE_TRY(stagingBuffer->invalidate(contextVk));
31033140

3104-
const gl::State &glState = contextVk->getState();
3105-
gl::Buffer *packBuffer = glState.getTargetBuffer(gl::BufferBinding::PixelPack);
3106-
if (packBuffer != nullptr)
3141+
if (packPixelsParams.packBuffer)
31073142
{
31083143
// Must map the PBO in order to read its contents (and then unmap it later)
3109-
BufferVk *packBufferVk = GetImpl(packBuffer);
3144+
BufferVk *packBufferVk = GetImpl(packPixelsParams.packBuffer);
31103145
void *mapPtr = nullptr;
31113146
ANGLE_TRY(packBufferVk->mapImpl(contextVk, &mapPtr));
31123147
uint8_t *dest = static_cast<uint8_t *>(mapPtr) + reinterpret_cast<ptrdiff_t>(pixels);

src/libANGLE/renderer/vulkan/vk_helpers.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -892,13 +892,24 @@ class ImageHelper final : public CommandGraphResource
892892
uint8_t **outDataPtr);
893893

894894
static angle::Result GetReadPixelsParams(ContextVk *contextVk,
895+
const gl::PixelPackState &packState,
896+
gl::Buffer *packBuffer,
895897
GLenum format,
896898
GLenum type,
897899
const gl::Rectangle &area,
898900
const gl::Rectangle &clippedArea,
899901
PackPixelsParams *paramsOut,
900902
GLuint *skipBytesOut);
901903

904+
angle::Result readPixelsForGetImage(ContextVk *contextVk,
905+
const gl::PixelPackState &packState,
906+
gl::Buffer *packBuffer,
907+
uint32_t level,
908+
uint32_t layer,
909+
GLenum format,
910+
GLenum type,
911+
void *pixels);
912+
902913
angle::Result readPixels(ContextVk *contextVk,
903914
const gl::Rectangle &area,
904915
const PackPixelsParams &packPixelsParams,

src/tests/gl_tests/GetImageTest.cpp

Lines changed: 80 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,31 +37,37 @@ class GetImageTestNoExtensions : public ANGLETest
3737
GetImageTestNoExtensions() { setExtensionsEnabled(false); }
3838
};
3939

40-
GLTexture InitSimpleTexture()
40+
GLTexture InitTextureWithSize(uint32_t size, void *pixelData)
4141
{
42-
std::vector<GLColor> pixelData(kSize * kSize, GLColor::red);
43-
4442
// Create a simple texture.
4543
GLTexture tex;
4644
glBindTexture(GL_TEXTURE_2D, tex);
47-
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
48-
pixelData.data());
45+
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixelData);
4946
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
5047
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
51-
5248
return tex;
5349
}
5450

55-
GLRenderbuffer InitSimpleRenderbuffer()
51+
GLTexture InitSimpleTexture()
52+
{
53+
std::vector<GLColor> pixelData(kSize * kSize, GLColor::red);
54+
return InitTextureWithSize(kSize, pixelData.data());
55+
}
56+
57+
GLRenderbuffer InitRenderbufferWithSize(uint32_t size)
5658
{
5759
// Create a simple renderbuffer.
5860
GLRenderbuffer renderbuf;
5961
glBindRenderbuffer(GL_RENDERBUFFER, renderbuf);
60-
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, kSize, kSize);
61-
62+
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, size, size);
6263
return renderbuf;
6364
}
6465

66+
GLRenderbuffer InitSimpleRenderbuffer()
67+
{
68+
return InitRenderbufferWithSize(kSize);
69+
}
70+
6571
// Test validation for the extension functions.
6672
TEST_P(GetImageTest, NegativeAPI)
6773
{
@@ -139,6 +145,71 @@ TEST_P(GetImageTest, NegativeAPI)
139145
}
140146
}
141147

148+
// Simple test for GetTexImage
149+
TEST_P(GetImageTest, GetTexImage)
150+
{
151+
// Verify the extension is enabled.
152+
ASSERT_TRUE(IsGLExtensionEnabled(kExtensionName));
153+
154+
constexpr uint32_t kSmallSize = 2;
155+
std::vector<GLColor> expectedData = {GLColor::red, GLColor::blue, GLColor::green,
156+
GLColor::yellow};
157+
158+
glViewport(0, 0, kSmallSize, kSmallSize);
159+
160+
// Draw once with simple texture.
161+
GLTexture tex = InitTextureWithSize(kSmallSize, expectedData.data());
162+
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
163+
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5, 1.0f, true);
164+
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
165+
ASSERT_GL_NO_ERROR();
166+
167+
// Pack pixels tightly.
168+
glPixelStorei(GL_PACK_ALIGNMENT, 1);
169+
170+
// Verify GetImage.
171+
std::vector<GLColor> actualData(kSmallSize * kSmallSize);
172+
glGetTexImageANGLE(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, actualData.data());
173+
EXPECT_GL_NO_ERROR();
174+
EXPECT_EQ(expectedData, actualData);
175+
}
176+
177+
// Simple test for GetRenderbufferImage
178+
TEST_P(GetImageTest, GetRenderbufferImage)
179+
{
180+
// Verify the extension is enabled.
181+
ASSERT_TRUE(IsGLExtensionEnabled(kExtensionName));
182+
183+
constexpr uint32_t kSmallSize = 2;
184+
std::vector<GLColor> expectedData = {GLColor::red, GLColor::blue, GLColor::green,
185+
GLColor::yellow};
186+
187+
glViewport(0, 0, kSmallSize, kSmallSize);
188+
189+
// Set up a simple Framebuffer with a Renderbuffer.
190+
GLRenderbuffer renderbuffer = InitRenderbufferWithSize(kSmallSize);
191+
GLFramebuffer framebuffer;
192+
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
193+
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer);
194+
ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
195+
196+
// Draw once with simple texture.
197+
GLTexture tex = InitTextureWithSize(kSmallSize, expectedData.data());
198+
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
199+
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5, 1.0f, true);
200+
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
201+
ASSERT_GL_NO_ERROR();
202+
203+
// Pack pixels tightly.
204+
glPixelStorei(GL_PACK_ALIGNMENT, 1);
205+
206+
// Verify GetImage.
207+
std::vector<GLColor> actualData(kSmallSize * kSmallSize);
208+
glGetRenderbufferImageANGLE(GL_RENDERBUFFER, GL_RGBA, GL_UNSIGNED_BYTE, actualData.data());
209+
EXPECT_GL_NO_ERROR();
210+
EXPECT_EQ(expectedData, actualData);
211+
}
212+
142213
// Verifies that the extension enums and entry points are invalid when the extension is disabled.
143214
TEST_P(GetImageTestNoExtensions, EntryPointsInactive)
144215
{

0 commit comments

Comments
 (0)