Add love.graphics.copyTextureToBuffer and copyBufferToTexture.

This commit is contained in:
Alex Szpakowski
2021-12-28 12:46:56 -04:00
parent d7bfc2ebcb
commit 52101b2563
11 changed files with 344 additions and 4 deletions
+4 -1
View File
@@ -1640,7 +1640,10 @@ void Graphics::initCapabilities()
capabilities.features[FEATURE_INSTANCING] = gl.isInstancingSupported();
capabilities.features[FEATURE_TEXEL_BUFFER] = gl.isBufferUsageSupported(BUFFERUSAGE_TEXEL);
capabilities.features[FEATURE_COPY_BUFFER] = gl.isCopyBufferSupported();
static_assert(FEATURE_MAX_ENUM == 12, "Graphics::initCapabilities must be updated when adding a new graphics feature!");
capabilities.features[FEATURE_COPY_BUFFER_TO_TEXTURE] = gl.isCopyBufferToTextureSupported();
capabilities.features[FEATURE_COPY_TEXTURE_TO_BUFFER] = gl.isCopyTextureToBufferSupported();
capabilities.features[FEATURE_COPY_RENDER_TARGET_TO_BUFFER] = gl.isCopyRenderTargetToBufferSupported();
static_assert(FEATURE_MAX_ENUM == 15, "Graphics::initCapabilities must be updated when adding a new graphics feature!");
capabilities.limits[LIMIT_POINT_SIZE] = gl.getMaxPointSize();
capabilities.limits[LIMIT_TEXTURE_SIZE] = gl.getMax2DTextureSize();
+18
View File
@@ -1530,6 +1530,24 @@ bool OpenGL::isCopyBufferSupported() const
return GLAD_VERSION_3_1 || GLAD_ES_VERSION_3_0;
}
bool OpenGL::isCopyBufferToTextureSupported() const
{
// Requires pixel unpack buffer binding support.
return GLAD_VERSION_2_0 || GLAD_ES_VERSION_3_0;
}
bool OpenGL::isCopyTextureToBufferSupported() const
{
// Requires glGetTextureSubImage support.
return GLAD_VERSION_4_5;
}
bool OpenGL::isCopyRenderTargetToBufferSupported() const
{
// Requires pixel pack buffer binding support.
return GLAD_VERSION_2_0 || GLAD_ES_VERSION_3_0;
}
int OpenGL::getMax2DTextureSize() const
{
return std::max(max2DTextureSize, 1);
+3
View File
@@ -372,6 +372,9 @@ public:
bool isBaseVertexSupported() const;
bool isMultiFormatMRTSupported() const;
bool isCopyBufferSupported() const;
bool isCopyBufferToTextureSupported() const;
bool isCopyTextureToBufferSupported() const;
bool isCopyRenderTargetToBufferSupported() const;
/**
* Returns the maximum supported width or height of a texture.
+70
View File
@@ -22,6 +22,7 @@
#include "graphics/Graphics.h"
#include "Graphics.h"
#include "Buffer.h"
#include "common/int.h"
// STD
@@ -524,6 +525,75 @@ void Texture::readbackImageData(love::image::ImageData *data, int slice, int mip
gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, current_fbo);
}
void Texture::copyFromBuffer(love::graphics::Buffer *source, size_t sourceoffset, int sourcewidth, size_t size, int slice, int mipmap, const Rect &rect)
{
// Higher level code does validation.
GLuint glbuffer = (GLuint) source->getHandle();
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, glbuffer);
if (!isCompressed()) // Not supported in GL with compressed textures...
glPixelStorei(GL_UNPACK_ROW_LENGTH, sourcewidth);
// glTexSubImage and friends copy from the active pixel_unpack_buffer by
// treating the pointer as a byte offset.
const uint8 *byteoffset = (const uint8 *)(ptrdiff_t)sourceoffset;
uploadByteData(format, byteoffset, size, mipmap, slice, rect);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
}
void Texture::copyToBuffer(love::graphics::Buffer *dest, int slice, int mipmap, const Rect &rect, size_t destoffset, int destwidth, size_t size)
{
// Higher level code does validation.
GLuint glbuffer = (GLuint) dest->getHandle();
glBindBuffer(GL_PIXEL_PACK_BUFFER, glbuffer);
if (!isCompressed()) // Not supported in GL with compressed textures...
glPixelStorei(GL_PACK_ROW_LENGTH, destwidth);
gl.bindTextureToUnit(this, 0, false);
bool isSRGB = false;
OpenGL::TextureFormat fmt = gl.convertPixelFormat(format, false, isSRGB);
// glTexSubImage and friends copy from the active pixel_unpack_buffer by
// treating the pointer as a byte offset.
uint8 *byteoffset = (uint8 *)(ptrdiff_t)destoffset;
if (GLAD_VERSION_4_5)
{
if (isCompressed())
glGetCompressedTextureSubImage(texture, mipmap, rect.x, rect.y, slice, rect.w, rect.h, 1, size, byteoffset);
else
glGetTextureSubImage(texture, mipmap, rect.x, rect.y, slice, rect.w, rect.h, 1, fmt.externalformat, fmt.type, size, byteoffset);
}
else if (fbo)
{
GLuint current_fbo = gl.getFramebuffer(OpenGL::FRAMEBUFFER_ALL);
gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, getFBO());
if (slice > 0 || mipmap > 0)
{
int layer = texType == TEXTURE_CUBE ? 0 : slice;
int face = texType == TEXTURE_CUBE ? slice : 0;
gl.framebufferTexture(GL_COLOR_ATTACHMENT0, texType, texture, mipmap, layer, face);
}
glReadPixels(rect.x, rect.y, rect.w, rect.h, fmt.externalformat, fmt.type, byteoffset);
if (slice > 0 || mipmap > 0)
gl.framebufferTexture(GL_COLOR_ATTACHMENT0, texType, texture, 0, 0, 0);
gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, current_fbo);
}
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
}
void Texture::setSamplerState(const SamplerState &s)
{
if (s.depthSampleMode.hasValue && !gl.isDepthCompareSampleSupported())
+3
View File
@@ -46,6 +46,9 @@ public:
bool loadVolatile() override;
void unloadVolatile() override;
void copyFromBuffer(love::graphics::Buffer *source, size_t sourceoffset, int sourcewidth, size_t size, int slice, int mipmap, const Rect &rect) override;
void copyToBuffer(love::graphics::Buffer *dest, int slice, int mipmap, const Rect &rect, size_t destoffset, int destwidth, size_t size) override;
void setSamplerState(const SamplerState &s) override;
ptrdiff_t getHandle() const override;