mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-24 05:49:58 +00:00
Move GL readback to a Thin3D abstraction
This commit is contained in:
parent
2d94d45389
commit
5bbe0eb69a
@ -599,12 +599,12 @@ void FramebufferManagerD3D11::ReadFramebufferToMemory(VirtualFramebuffer *vfb, b
|
||||
OptimizeDownloadRange(vfb, x, y, w, h);
|
||||
if (vfb->renderWidth == vfb->width && vfb->renderHeight == vfb->height) {
|
||||
// No need to blit
|
||||
PackFramebufferD3D11_(vfb, x, y, w, h);
|
||||
PackFramebufferSync_(vfb, x, y, w, h);
|
||||
}
|
||||
else {
|
||||
VirtualFramebuffer *nvfb = FindDownloadTempBuffer(vfb);
|
||||
BlitFramebuffer(nvfb, x, y, vfb, x, y, w, h, 0);
|
||||
PackFramebufferD3D11_(nvfb, x, y, w, h);
|
||||
PackFramebufferSync_(nvfb, x, y, w, h);
|
||||
}
|
||||
|
||||
textureCacheD3D11_->ForgetLastTexture();
|
||||
@ -639,7 +639,7 @@ void FramebufferManagerD3D11::DownloadFramebufferForClut(u32 fb_address, u32 loa
|
||||
VirtualFramebuffer *nvfb = FindDownloadTempBuffer(vfb);
|
||||
BlitFramebuffer(nvfb, x, y, vfb, x, y, w, h, 0);
|
||||
|
||||
PackFramebufferD3D11_(nvfb, x, y, w, h);
|
||||
PackFramebufferSync_(nvfb, x, y, w, h);
|
||||
|
||||
textureCacheD3D11_->ForgetLastTexture();
|
||||
RebindFramebuffer();
|
||||
@ -815,7 +815,7 @@ void ConvertFromRGBA8888(u8 *dst, u8 *src, u32 dstStride, u32 srcStride, u32 wid
|
||||
// This function takes an already correctly-sized framebuffer and packs it into RAM.
|
||||
// Does not need to account for scaling.
|
||||
// Color conversion is currently done on CPU but should be done on GPU.
|
||||
void FramebufferManagerD3D11::PackFramebufferD3D11_(VirtualFramebuffer *vfb, int x, int y, int w, int h) {
|
||||
void FramebufferManagerD3D11::PackFramebufferSync_(VirtualFramebuffer *vfb, int x, int y, int w, int h) {
|
||||
if (!vfb->fbo) {
|
||||
ERROR_LOG_REPORT_ONCE(vfbfbozero, SCEGE, "PackFramebufferD3D11_: vfb->fbo == 0");
|
||||
return;
|
||||
@ -824,12 +824,16 @@ void FramebufferManagerD3D11::PackFramebufferD3D11_(VirtualFramebuffer *vfb, int
|
||||
const u32 fb_address = (0x04000000) | vfb->fb_address;
|
||||
const int dstBpp = vfb->format == GE_FORMAT_8888 ? 4 : 2;
|
||||
|
||||
// TODO: Handle the other formats? We don't currently create them, I think.
|
||||
const int dstByteOffset = (y * vfb->fb_stride + x) * dstBpp;
|
||||
u8 *destPtr = Memory::GetPointer(fb_address + dstByteOffset);
|
||||
|
||||
// We always need to convert from the framebuffer native format.
|
||||
// Right now that's always 8888.
|
||||
DEBUG_LOG(G3D, "Reading framebuffer to mem, fb_address = %08x", fb_address);
|
||||
ID3D11Texture2D *colorTex = (ID3D11Texture2D *)draw_->GetFramebufferAPITexture(vfb->fbo, Draw::FB_COLOR_BIT, 0);
|
||||
|
||||
// TODO: Only copy the necessary rectangle.
|
||||
// Only copy the necessary rectangle.
|
||||
D3D11_BOX srcBox{ (UINT)x, (UINT)y, 0, (UINT)(x+w), (UINT)(y+h), 1 };
|
||||
context_->CopySubresourceRegion(packTexture_, 0, x, y, 0, colorTex, 0, &srcBox);
|
||||
|
||||
@ -843,11 +847,9 @@ void FramebufferManagerD3D11::PackFramebufferD3D11_(VirtualFramebuffer *vfb, int
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Handle the other formats? We don't currently create them, I think.
|
||||
const int srcByteOffset = y * map.RowPitch + x * 4;
|
||||
const int dstByteOffset = (y * vfb->fb_stride + x) * dstBpp;
|
||||
// Pixel size always 4 here because we always request BGRA8888.
|
||||
ConvertFromRGBA8888(Memory::GetPointer(fb_address + dstByteOffset), (u8 *)map.pData + srcByteOffset, vfb->fb_stride, map.RowPitch/4, w, h, vfb->format);
|
||||
ConvertFromRGBA8888(destPtr, (u8 *)map.pData + srcByteOffset, vfb->fb_stride, map.RowPitch/4, w, h, vfb->format);
|
||||
context_->Unmap(packTexture_, 0);
|
||||
}
|
||||
|
||||
|
@ -94,7 +94,7 @@ private:
|
||||
void BindPostShader(const PostShaderUniforms &uniforms) override;
|
||||
void Bind2DShader() override;
|
||||
void MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height, float &u1, float &v1) override;
|
||||
void PackFramebufferD3D11_(VirtualFramebuffer *vfb, int x, int y, int w, int h);
|
||||
void PackFramebufferSync_(VirtualFramebuffer *vfb, int x, int y, int w, int h);
|
||||
void PackDepthbuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h);
|
||||
void SimpleBlit(
|
||||
Draw::Framebuffer *dest, float destX1, float destY1, float destX2, float destY2,
|
||||
|
@ -843,39 +843,6 @@ static void LogReadPixelsError(GLenum error) {
|
||||
}
|
||||
#endif
|
||||
|
||||
static void SafeGLReadPixels(GLint x, GLint y, GLsizei w, GLsizei h, GLenum fmt, GLenum type, void *pixels) {
|
||||
CHECK_GL_ERROR_IF_DEBUG();
|
||||
|
||||
// Apply the correct alignment.
|
||||
if (fmt == GL_RGBA && type == GL_UNSIGNED_BYTE) {
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 4);
|
||||
} else if (fmt == GL_RGB && type == GL_UNSIGNED_BYTE) {
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
} else if (fmt == GL_DEPTH_COMPONENT && type == GL_FLOAT) {
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 4);
|
||||
} else if (fmt == GL_STENCIL_INDEX && type == GL_UNSIGNED_BYTE) {
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 2); // This seems dubious. 1?
|
||||
} else {
|
||||
// The remainders do their own calls for now.
|
||||
// glPixelStorei(GL_PACK_ALIGNMENT, 4);
|
||||
}
|
||||
|
||||
if (!gl_extensions.IsGLES || (gl_extensions.GLES3 && gl_extensions.gpuVendor != GPU_VENDOR_NVIDIA)) {
|
||||
// Some drivers seem to require we specify this. See #8254.
|
||||
glPixelStorei(GL_PACK_ROW_LENGTH, w);
|
||||
}
|
||||
|
||||
glReadPixels(x, y, w, h, fmt, type, pixels);
|
||||
#ifdef DEBUG_READ_PIXELS
|
||||
LogReadPixelsError(glGetError());
|
||||
#endif
|
||||
|
||||
if (!gl_extensions.IsGLES || gl_extensions.GLES3) {
|
||||
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
|
||||
}
|
||||
CHECK_GL_ERROR_IF_DEBUG();
|
||||
}
|
||||
|
||||
void FramebufferManagerGLES::PackFramebufferAsync_(VirtualFramebuffer *vfb) {
|
||||
CHECK_GL_ERROR_IF_DEBUG();
|
||||
const int MAX_PBO = 2;
|
||||
@ -935,15 +902,7 @@ void FramebufferManagerGLES::PackFramebufferAsync_(VirtualFramebuffer *vfb) {
|
||||
|
||||
// Order packing/readback of the framebuffer
|
||||
if (vfb) {
|
||||
GLuint pixelType, pixelFormat;
|
||||
|
||||
bool reverseOrder = gstate_c.Supports(GPU_PREFER_REVERSE_COLOR_ORDER);
|
||||
int pixelSize = 2, align = 2;
|
||||
if (vfb->format == GE_FORMAT_8888) {
|
||||
pixelSize = 4;
|
||||
align = 4;
|
||||
}
|
||||
|
||||
Draw::DataFormat dataFmt = Draw::DataFormat::UNDEFINED;
|
||||
switch (vfb->format) {
|
||||
case GE_FORMAT_4444:
|
||||
@ -960,49 +919,12 @@ void FramebufferManagerGLES::PackFramebufferAsync_(VirtualFramebuffer *vfb) {
|
||||
break;
|
||||
};
|
||||
|
||||
switch (vfb->format) {
|
||||
// GL_UNSIGNED_INT_8_8_8_8 returns A B G R (little-endian, tested in Nvidia card/x86 PC)
|
||||
// GL_UNSIGNED_BYTE returns R G B A in consecutive bytes ("big-endian"/not treated as 32-bit value)
|
||||
// We want R G B A, so we use *_REV for 16-bit formats and GL_UNSIGNED_BYTE for 32-bit
|
||||
case GE_FORMAT_4444: // 16 bit RGBA
|
||||
#ifdef USING_GLES2
|
||||
pixelType = GL_UNSIGNED_SHORT_4_4_4_4;
|
||||
#else
|
||||
pixelType = (reverseOrder ? GL_UNSIGNED_SHORT_4_4_4_4_REV : GL_UNSIGNED_SHORT_4_4_4_4);
|
||||
#endif
|
||||
pixelFormat = GL_RGBA;
|
||||
break;
|
||||
case GE_FORMAT_5551: // 16 bit RGBA
|
||||
#ifdef USING_GLES2
|
||||
pixelType = GL_UNSIGNED_SHORT_5_5_5_1;
|
||||
#else
|
||||
pixelType = (reverseOrder ? GL_UNSIGNED_SHORT_1_5_5_5_REV : GL_UNSIGNED_SHORT_5_5_5_1);
|
||||
#endif
|
||||
pixelFormat = GL_RGBA;
|
||||
break;
|
||||
case GE_FORMAT_565: // 16 bit RGB
|
||||
#ifdef USING_GLES2
|
||||
pixelType = GL_UNSIGNED_SHORT_5_6_5;
|
||||
#else
|
||||
pixelType = (reverseOrder ? GL_UNSIGNED_SHORT_5_6_5_REV : GL_UNSIGNED_SHORT_5_6_5);
|
||||
#endif
|
||||
pixelFormat = GL_RGB;
|
||||
break;
|
||||
case GE_FORMAT_8888: // 32 bit RGBA
|
||||
default:
|
||||
pixelType = GL_UNSIGNED_BYTE;
|
||||
pixelFormat = GL_RGBA;
|
||||
break;
|
||||
if (useCPU) {
|
||||
dataFmt = Draw::DataFormat::R8G8B8A8_UNORM;
|
||||
}
|
||||
|
||||
if (useCPU) {
|
||||
// If converting pixel formats on the CPU we'll always request RGBA8888
|
||||
// Otherwise we'll directly request the format we need and let the GPU sort it out
|
||||
pixelSize = 4;
|
||||
align = 4;
|
||||
pixelFormat = GL_RGBA;
|
||||
pixelType = GL_UNSIGNED_BYTE;
|
||||
}
|
||||
int pixelSize = (int)DataFormatSizeInBytes(dataFmt);
|
||||
int align = pixelSize;
|
||||
|
||||
// If using the CPU, we need 4 bytes per pixel always.
|
||||
u32 bufSize = vfb->fb_stride * vfb->height * pixelSize;
|
||||
@ -1023,8 +945,8 @@ void FramebufferManagerGLES::PackFramebufferAsync_(VirtualFramebuffer *vfb) {
|
||||
pixelBufObj_[currentPBO_].maxSize = bufSize;
|
||||
}
|
||||
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, align);
|
||||
SafeGLReadPixels(0, 0, vfb->fb_stride, vfb->height, pixelFormat, pixelType, 0);
|
||||
// TODO: Change to CopyFramebufferToBuffer with a proper pointer.
|
||||
draw_->CopyFramebufferToMemorySync(0, 0, vfb->fb_stride, vfb->height, dataFmt, nullptr);
|
||||
|
||||
unbind = true;
|
||||
|
||||
@ -1083,14 +1005,14 @@ void FramebufferManagerGLES::PackFramebufferSync_(VirtualFramebuffer *vfb, int x
|
||||
|
||||
if (packed) {
|
||||
DEBUG_LOG(FRAMEBUF, "Reading framebuffer to mem, bufSize = %u, fb_address = %08x", bufSize, fb_address);
|
||||
|
||||
SafeGLReadPixels(0, y, h == 1 ? packWidth : vfb->fb_stride, h, GL_RGBA, GL_UNSIGNED_BYTE, packed);
|
||||
|
||||
int packW = h == 1 ? packWidth : vfb->fb_stride; // TODO: What's this about?
|
||||
draw_->CopyFramebufferToMemorySync(0, y, packW, h, Draw::DataFormat::R8G8B8A8_UNORM, packed);
|
||||
if (convert) {
|
||||
ConvertFromRGBA8888(dst, packed, vfb->fb_stride, vfb->fb_stride, packWidth, h, vfb->format);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Move this into Thin3d.
|
||||
if (gl_extensions.GLES3 && glInvalidateFramebuffer != nullptr) {
|
||||
#ifdef USING_GLES2
|
||||
// GLES3 doesn't support using GL_READ_FRAMEBUFFER here.
|
||||
@ -1126,7 +1048,7 @@ void FramebufferManagerGLES::PackDepthbuffer(VirtualFramebuffer *vfb, int x, int
|
||||
|
||||
DEBUG_LOG(FRAMEBUF, "Reading depthbuffer to mem at %08x for vfb=%08x", z_address, vfb->fb_address);
|
||||
|
||||
SafeGLReadPixels(0, y, h == 1 ? packWidth : vfb->z_stride, h, GL_DEPTH_COMPONENT, GL_FLOAT, convBuf_);
|
||||
draw_->CopyFramebufferToMemorySync(0, y, h == 1 ? packWidth : vfb->z_stride, h, Draw::DataFormat::D32F, convBuf_);
|
||||
|
||||
int dstByteOffset = y * vfb->fb_stride * sizeof(u16);
|
||||
u16 *depth = (u16 *)Memory::GetPointer(z_address + dstByteOffset);
|
||||
@ -1287,7 +1209,7 @@ bool FramebufferManagerGLES::GetFramebuffer(u32 fb_address, int fb_stride, GEBuf
|
||||
if (gl_extensions.GLES3 || !gl_extensions.IsGLES)
|
||||
glReadBuffer(GL_COLOR_ATTACHMENT0);
|
||||
|
||||
SafeGLReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, buffer.GetData());
|
||||
draw_->CopyFramebufferToMemorySync(0, 0, w, h, Draw::DataFormat::R8G8B8A8_UNORM, buffer.GetData());
|
||||
|
||||
// We may have blitted to a temp FBO.
|
||||
RebindFramebuffer();
|
||||
@ -1299,9 +1221,9 @@ bool FramebufferManagerGLES::GetOutputFramebuffer(GPUDebugBuffer &buffer) {
|
||||
int pw = PSP_CoreParameter().pixelWidth;
|
||||
int ph = PSP_CoreParameter().pixelHeight;
|
||||
|
||||
// The backbuffer is flipped.
|
||||
// The backbuffer is flipped (last bool)
|
||||
buffer.Allocate(pw, ph, GPU_DBG_FORMAT_888_RGB, true);
|
||||
SafeGLReadPixels(0, 0, pw, ph, GL_RGB, GL_UNSIGNED_BYTE, buffer.GetData());
|
||||
draw_->CopyFramebufferToMemorySync(0, 0, pw, ph, Draw::DataFormat::R8G8B8_UNORM, buffer.GetData());
|
||||
CHECK_GL_ERROR_IF_DEBUG();
|
||||
return true;
|
||||
}
|
||||
@ -1329,9 +1251,7 @@ bool FramebufferManagerGLES::GetDepthbuffer(u32 fb_address, int fb_stride, u32 z
|
||||
}
|
||||
if (vfb->fbo)
|
||||
draw_->BindFramebufferForRead(vfb->fbo);
|
||||
if (gl_extensions.GLES3 || !gl_extensions.IsGLES)
|
||||
glReadBuffer(GL_COLOR_ATTACHMENT0);
|
||||
SafeGLReadPixels(0, 0, vfb->renderWidth, vfb->renderHeight, GL_DEPTH_COMPONENT, GL_FLOAT, buffer.GetData());
|
||||
draw_->CopyFramebufferToMemorySync(0, 0, vfb->renderWidth, vfb->renderHeight, Draw::DataFormat::D32F, buffer.GetData());
|
||||
CHECK_GL_ERROR_IF_DEBUG();
|
||||
return true;
|
||||
}
|
||||
@ -1353,9 +1273,7 @@ bool FramebufferManagerGLES::GetStencilbuffer(u32 fb_address, int fb_stride, GPU
|
||||
buffer.Allocate(vfb->renderWidth, vfb->renderHeight, GPU_DBG_FORMAT_8BIT, !useBufferedRendering_);
|
||||
if (vfb->fbo)
|
||||
draw_->BindFramebufferForRead(vfb->fbo);
|
||||
if (gl_extensions.GLES3 || !gl_extensions.IsGLES)
|
||||
glReadBuffer(GL_COLOR_ATTACHMENT0);
|
||||
SafeGLReadPixels(0, 0, vfb->renderWidth, vfb->renderHeight, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, buffer.GetData());
|
||||
draw_->CopyFramebufferToMemorySync(0, 0, vfb->renderWidth, vfb->renderHeight, Draw::DataFormat::S8, buffer.GetData());
|
||||
CHECK_GL_ERROR_IF_DEBUG();
|
||||
return true;
|
||||
#else
|
||||
|
@ -617,6 +617,12 @@ public:
|
||||
|
||||
virtual void CopyFramebufferImage(Framebuffer *src, int level, int x, int y, int z, Framebuffer *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, int channelBits) = 0;
|
||||
virtual bool BlitFramebuffer(Framebuffer *src, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dst, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter) = 0;
|
||||
virtual bool CopyFramebufferToBuffer(Framebuffer *src, Buffer *buffer, Draw::DataFormat bufferFormat) {
|
||||
return false;
|
||||
}
|
||||
virtual bool CopyFramebufferToMemorySync(int x, int y, int w, int h, Draw::DataFormat format, void *pixels) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// These functions should be self explanatory.
|
||||
// Binding a zero render target means binding the backbuffer.
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <cassert>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "math/dataconv.h"
|
||||
@ -465,6 +466,7 @@ public:
|
||||
|
||||
void CopyFramebufferImage(Framebuffer *src, int level, int x, int y, int z, Framebuffer *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, int channelBits) override;
|
||||
bool BlitFramebuffer(Framebuffer *src, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dst, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter) override;
|
||||
bool CopyFramebufferToMemorySync(int x, int y, int w, int h, Draw::DataFormat format, void *pixels) override;
|
||||
|
||||
// These functions should be self explanatory.
|
||||
void BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp) override;
|
||||
@ -729,63 +731,85 @@ void OpenGLTexture::AutoGenMipmaps() {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Also output storage format (GL_RGB8 etc) for modern GL usage.
|
||||
static bool Thin3DFormatToFormatAndType(DataFormat fmt, GLuint &internalFormat, GLuint &format, GLuint &type) {
|
||||
// TODO: Also output storage format (GL_RGBA8 etc) for modern GL usage.
|
||||
static bool Thin3DFormatToFormatAndType(DataFormat fmt, GLuint &internalFormat, GLuint &format, GLuint &type, int &alignment) {
|
||||
alignment = 4;
|
||||
switch (fmt) {
|
||||
case DataFormat::R8G8B8A8_UNORM:
|
||||
internalFormat = GL_RGBA;
|
||||
format = GL_RGBA;
|
||||
type = GL_UNSIGNED_BYTE;
|
||||
return true;
|
||||
break;
|
||||
|
||||
case DataFormat::D32F:
|
||||
internalFormat = GL_DEPTH_COMPONENT;
|
||||
format = GL_DEPTH_COMPONENT;
|
||||
type = GL_FLOAT;
|
||||
break;
|
||||
|
||||
case DataFormat::S8:
|
||||
internalFormat = GL_STENCIL_INDEX;
|
||||
format = GL_STENCIL_INDEX;
|
||||
type = GL_UNSIGNED_BYTE;
|
||||
alignment = 1;
|
||||
break;
|
||||
|
||||
case DataFormat::R8G8B8_UNORM:
|
||||
internalFormat = GL_RGB;
|
||||
format = GL_RGB;
|
||||
type = GL_UNSIGNED_BYTE;
|
||||
return true;
|
||||
alignment = 1;
|
||||
break;
|
||||
|
||||
case DataFormat::B4G4R4A4_UNORM_PACK16:
|
||||
internalFormat = GL_RGBA;
|
||||
format = GL_RGBA;
|
||||
type = GL_UNSIGNED_SHORT_4_4_4_4;
|
||||
return true;
|
||||
alignment = 2;
|
||||
break;
|
||||
|
||||
case DataFormat::B5G6R5_UNORM_PACK16:
|
||||
internalFormat = GL_RGB;
|
||||
format = GL_RGB;
|
||||
type = GL_UNSIGNED_SHORT_5_6_5;
|
||||
return true;
|
||||
alignment = 2;
|
||||
break;
|
||||
|
||||
case DataFormat::B5G5R5A1_UNORM_PACK16:
|
||||
internalFormat = GL_RGBA;
|
||||
format = GL_RGBA;
|
||||
type = GL_UNSIGNED_SHORT_5_5_5_1;
|
||||
return true;
|
||||
alignment = 2;
|
||||
break;
|
||||
|
||||
#ifndef USING_GLES2
|
||||
case DataFormat::A4R4G4B4_UNORM_PACK16:
|
||||
internalFormat = GL_RGBA;
|
||||
format = GL_RGBA;
|
||||
type = GL_UNSIGNED_SHORT_4_4_4_4_REV;
|
||||
return true;
|
||||
alignment = 2;
|
||||
break;
|
||||
|
||||
case DataFormat::R5G6B5_UNORM_PACK16:
|
||||
internalFormat = GL_RGB;
|
||||
format = GL_RGB;
|
||||
type = GL_UNSIGNED_SHORT_5_6_5_REV;
|
||||
return true;
|
||||
alignment = 2;
|
||||
break;
|
||||
|
||||
case DataFormat::A1R5G5B5_UNORM_PACK16:
|
||||
internalFormat = GL_RGBA;
|
||||
format = GL_RGBA;
|
||||
type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
|
||||
return true;
|
||||
alignment = 2;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
ELOG("Thin3d GL: Unsupported texture format %d", (int)fmt);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void OpenGLTexture::SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data) {
|
||||
@ -799,7 +823,8 @@ void OpenGLTexture::SetImageData(int x, int y, int z, int width, int height, int
|
||||
GLuint internalFormat;
|
||||
GLuint format;
|
||||
GLuint type;
|
||||
if (!Thin3DFormatToFormatAndType(format_, internalFormat, format, type)) {
|
||||
int alignment;
|
||||
if (!Thin3DFormatToFormatAndType(format_, internalFormat, format, type, alignment)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -815,6 +840,40 @@ void OpenGLTexture::SetImageData(int x, int y, int z, int width, int height, int
|
||||
CHECK_GL_ERROR_IF_DEBUG();
|
||||
}
|
||||
|
||||
bool OpenGLContext::CopyFramebufferToMemorySync(int x, int y, int w, int h, Draw::DataFormat dataFormat, void *pixels) {
|
||||
// Reads from the "bound for read" framebuffer.
|
||||
if (gl_extensions.GLES3 || !gl_extensions.IsGLES)
|
||||
glReadBuffer(GL_COLOR_ATTACHMENT0);
|
||||
|
||||
CHECK_GL_ERROR_IF_DEBUG();
|
||||
|
||||
GLuint internalFormat;
|
||||
GLuint format;
|
||||
GLuint type;
|
||||
int alignment;
|
||||
if (!Thin3DFormatToFormatAndType(dataFormat, internalFormat, format, type, alignment)) {
|
||||
assert(false);
|
||||
}
|
||||
// Apply the correct alignment.
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, alignment);
|
||||
if (!gl_extensions.IsGLES || (gl_extensions.GLES3 && gl_extensions.gpuVendor != GPU_VENDOR_NVIDIA)) {
|
||||
// Some drivers seem to require we specify this. See #8254.
|
||||
glPixelStorei(GL_PACK_ROW_LENGTH, w);
|
||||
}
|
||||
|
||||
glReadPixels(x, y, w, h, format, type, pixels);
|
||||
#ifdef DEBUG_READ_PIXELS
|
||||
LogReadPixelsError(glGetError());
|
||||
#endif
|
||||
|
||||
if (!gl_extensions.IsGLES || gl_extensions.GLES3) {
|
||||
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
|
||||
}
|
||||
CHECK_GL_ERROR_IF_DEBUG();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Texture *OpenGLContext::CreateTexture(const TextureDesc &desc) {
|
||||
return new OpenGLTexture(desc);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user