Skip to content

Commit

Permalink
[Render/Texture2D] Recovering the image can now work with OpenGL ES
Browse files Browse the repository at this point in the history
- The workaround is to set the texture as a read framebuffer output, then recover this
  - It was done in tests until now and has been moved to the actual function
  • Loading branch information
Razakhel committed Mar 3, 2024
1 parent af39bfa commit 1643846
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 26 deletions.
2 changes: 0 additions & 2 deletions include/RaZ/Render/Texture.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,14 +158,12 @@ class Texture2D final : public Texture {
/// Fills the texture with a single color.
/// \param color Color to fill the texture with.
void fill(const Color& color);
#if !defined(USE_OPENGL_ES)
/// Retrieves the texture's data from the GPU.
/// \warning The pixel storage pack & unpack alignments should be set to 1 in order to recover actual pixels.
/// \see Renderer::setPixelStorage()
/// \warning Retrieving an image from the GPU is slow; use this function with caution.
/// \return Recovered image.
Image recoverImage() const;
#endif

private:
void load() const override;
Expand Down
26 changes: 19 additions & 7 deletions src/RaZ/Render/Texture.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#include "RaZ/Data/Color.hpp"
#include "RaZ/Data/Image.hpp"
#if defined(USE_OPENGL_ES)
#include "RaZ/Render/Framebuffer.hpp"
#endif
#include "RaZ/Render/Renderer.hpp"
#include "RaZ/Render/Texture.hpp"
#include "RaZ/Utils/Logger.hpp"
Expand Down Expand Up @@ -321,21 +324,30 @@ void Texture2D::fill(const Color& color) {
unbind();
}

#if !defined(USE_OPENGL_ES) // Renderer::recoverTextureData() is unavailable with OpenGL ES
Image Texture2D::recoverImage() const {
Image img(m_width, m_height, static_cast<ImageColorspace>(m_colorspace), (m_dataType == TextureDataType::BYTE ? ImageDataType::BYTE : ImageDataType::FLOAT));

const PixelDataType pixelDataType = (m_dataType == TextureDataType::BYTE ? PixelDataType::UBYTE : PixelDataType::FLOAT);

#if !defined(USE_OPENGL_ES)
bind();
Renderer::recoverTextureData(TextureType::TEXTURE_2D,
0,
recoverFormat(m_colorspace),
(m_dataType == TextureDataType::BYTE ? PixelDataType::UBYTE : PixelDataType::FLOAT),
img.getDataPtr());
Renderer::recoverTextureData(TextureType::TEXTURE_2D, 0, recoverFormat(m_colorspace), pixelDataType, img.getDataPtr());
unbind();
#else
// Recovering an image directly from a texture (glGetTexImage()) is not possible with OpenGL ES; a framebuffer must be used to read the texture from instead
// See: https://stackoverflow.com/a/53993894/3292304

const Framebuffer dummyFramebuffer;
Renderer::bindFramebuffer(dummyFramebuffer.getIndex(), FramebufferType::READ_FRAMEBUFFER);

Renderer::setFramebufferTexture2D(FramebufferAttachment::COLOR0, m_index, 0, TextureType::TEXTURE_2D, FramebufferType::READ_FRAMEBUFFER);
Renderer::recoverFrame(m_width, m_height, recoverFormat(m_colorspace), pixelDataType, img.getDataPtr());

Renderer::unbindFramebuffer(FramebufferType::READ_FRAMEBUFFER);
#endif

return img;
}
#endif

void Texture2D::load() const {
if (m_colorspace == TextureColorspace::INVALID)
Expand Down
17 changes: 0 additions & 17 deletions tests/src/RaZ/Render/RenderProcess.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,24 +25,7 @@ Raz::Image renderFrame(Raz::World& world, const Raz::Texture2DPtr& output, const
// fail under Linux (as the second rendered frame of each test might be empty)
world.update({});

#if !defined(USE_OPENGL_ES)
Raz::Image renderedImg = output->recoverImage();
#else
// Recovering an image directly from a texture (glReadPixels()) is not possible with OpenGL ES; a framebuffer must be used to read the texture from instead
// See: https://stackoverflow.com/a/53993894/3292304
const Raz::Framebuffer intermFramebuffer;
Raz::Renderer::bindFramebuffer(intermFramebuffer.getIndex(), Raz::FramebufferType::READ_FRAMEBUFFER);
Raz::Renderer::setFramebufferTexture2D(Raz::FramebufferAttachment::COLOR0,
output->getIndex(),
0,
Raz::TextureType::TEXTURE_2D,
Raz::FramebufferType::READ_FRAMEBUFFER);

Raz::Image renderedImg(output->getWidth(), output->getHeight(), Raz::ImageColorspace::RGB, Raz::ImageDataType::BYTE);
Raz::Renderer::recoverFrame(output->getWidth(), output->getHeight(), Raz::TextureFormat::RGB, Raz::PixelDataType::UBYTE, renderedImg.getDataPtr());

Raz::Renderer::unbindFramebuffer(Raz::FramebufferType::READ_FRAMEBUFFER);
#endif

if (!renderedImgPath.isEmpty())
Raz::ImageFormat::save(renderedImgPath, renderedImg, true);
Expand Down

0 comments on commit 1643846

Please sign in to comment.