diff --git a/projects/msvc12/GLideN64.vcxproj b/projects/msvc12/GLideN64.vcxproj index bdcd10b7..ac3f13a6 100644 --- a/projects/msvc12/GLideN64.vcxproj +++ b/projects/msvc12/GLideN64.vcxproj @@ -290,6 +290,7 @@ + diff --git a/projects/msvc12/GLideN64.vcxproj.filters b/projects/msvc12/GLideN64.vcxproj.filters index e3b6c48d..0209945a 100644 --- a/projects/msvc12/GLideN64.vcxproj.filters +++ b/projects/msvc12/GLideN64.vcxproj.filters @@ -296,6 +296,9 @@ Source Files\Graphics\OpenGL + + Source Files\Graphics + Source Files\Graphics diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ec9c5328..d89c05a9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -65,6 +65,7 @@ set(GLideN64_SOURCES DepthBufferRender/DepthBufferRender.cpp common/CommonAPIImpl_common.cpp Graphics/Context.cpp + Graphics/ColorBufferReader.cpp Graphics/CombinerProgram.cpp Graphics/ObjectHandle.cpp Graphics/OpenGLContext/GLFunctions.cpp diff --git a/src/Graphics/ColorBufferReader.cpp b/src/Graphics/ColorBufferReader.cpp new file mode 100644 index 00000000..2fb43ea0 --- /dev/null +++ b/src/Graphics/ColorBufferReader.cpp @@ -0,0 +1,89 @@ + +#include "ColorBufferReader.h" +#include "FramebufferTextureFormats.h" +#include "Context.h" +#include "Parameters.h" +#include +#include + +namespace graphics { + + ColorBufferReader::ColorBufferReader(CachedTexture * _pTexture) + : m_pTexture(_pTexture) + { + m_pixelData.resize(m_pTexture->textureBytes); + m_tempPixelData.resize(m_pTexture->textureBytes); + } + + const u8* ColorBufferReader::_convertFloatTextureBuffer(const u8* _gpuData, u32 _width, u32 _height, + u32 _heightOffset, u32 _stride) + { + std::copy_n(_gpuData, m_tempPixelData.size(), m_tempPixelData.data()); + u8* pixelDataAlloc = m_pixelData.data(); + float* pixelData = reinterpret_cast(m_tempPixelData.data()); + const u32 colorsPerPixel = 4; + const u32 widthPixels = _width * colorsPerPixel; + const u32 stridePixels = _stride * colorsPerPixel; + + for (u32 index = 0; index < _height; ++index) { + for (u32 widthIndex = 0; widthIndex < widthPixels; ++widthIndex) { + u8& dest = *(pixelDataAlloc + index*widthPixels + widthIndex); + float& src = *(pixelData + (index+_heightOffset)*stridePixels + widthIndex); + dest = static_cast(src*255.0); + } + } + + return pixelDataAlloc; + } + + const u8* ColorBufferReader::_convertIntegerTextureBuffer(const u8* _gpuData, u32 _width, u32 _height, + u32 _heightOffset, u32 _stride) + { + const u32 colorsPerPixel = 4; + const u32 widthBytes = _width * colorsPerPixel; + const u32 strideBytes = _stride * colorsPerPixel; + + u8* pixelDataAlloc = m_pixelData.data(); + for (u32 lnIndex = 0; lnIndex < _height; ++lnIndex) { + memcpy(pixelDataAlloc + lnIndex*widthBytes, _gpuData + ((lnIndex+_heightOffset)*strideBytes), widthBytes); + } + + return pixelDataAlloc; + } + + + const u8 * ColorBufferReader::readPixels(s32 _x0, s32 _y0, u32 _width, u32 _height, u32 _size, bool _sync) + { + const FramebufferTextureFormats & fbTexFormat = gfxContext.getFramebufferTextureFormats(); + + ReadColorBufferParams params; + params.x0 = _x0; + params.y0 = _y0; + params.width = _width; + params.height = _height; + params.sync = _sync; + + if (_size > G_IM_SIZ_8b) { + params.colorFormat = fbTexFormat.colorFormat; + params.colorType = fbTexFormat.colorType; + params.colorFormatBytes = fbTexFormat.colorFormatBytes; + } else { + params.colorFormat = fbTexFormat.monochromeFormat; + params.colorType = fbTexFormat.monochromeType; + params.colorFormatBytes = fbTexFormat.monochromeFormatBytes; + } + + u32 heightOffset = 0; + u32 stride = 0; + const u8* pixelData = _readPixels(params, heightOffset, stride); + + if (pixelData == nullptr) + return nullptr; + + if(params.colorType == datatype::FLOAT) { + return _convertFloatTextureBuffer(pixelData, params.width, params.height, heightOffset, stride); + } else { + return _convertIntegerTextureBuffer(pixelData, params.width, params.height, heightOffset, stride); + } + } +} diff --git a/src/Graphics/ColorBufferReader.h b/src/Graphics/ColorBufferReader.h index 157edd6a..529c5c24 100644 --- a/src/Graphics/ColorBufferReader.h +++ b/src/Graphics/ColorBufferReader.h @@ -8,18 +8,32 @@ namespace graphics { class ColorBufferReader { public: - ColorBufferReader(CachedTexture * _pTexture) - : m_pTexture(_pTexture) { - m_pixelData.resize(m_pTexture->textureBytes); - } - virtual ~ColorBufferReader() {} + ColorBufferReader(CachedTexture * _pTexture); + virtual ~ColorBufferReader() = default; - virtual u8 * readPixels(s32 _x0, s32 _y0, u32 _width, u32 _height, u32 _size, bool _sync) = 0; + virtual const u8 * readPixels(s32 _x0, s32 _y0, u32 _width, u32 _height, u32 _size, bool _sync); virtual void cleanUp() = 0; protected: + struct ReadColorBufferParams { + s32 x0; + s32 y0; + u32 width; + u32 height; + bool sync; + ColorFormatParam colorFormat; + DatatypeParam colorType; + u32 colorFormatBytes; + }; + CachedTexture * m_pTexture; std::vector m_pixelData; + std::vector m_tempPixelData; + +private: + const u8* _convertFloatTextureBuffer(const u8* _gpuData, u32 _width, u32 _height, u32 _heightOffset, u32 _stride); + const u8* _convertIntegerTextureBuffer(const u8* _gpuData, u32 _width, u32 _height,u32 _heightOffset, u32 _stride); + virtual const u8 * _readPixels(const ReadColorBufferParams& _params, u32& _heightOffset, u32& _stride) = 0; }; } diff --git a/src/Graphics/OpenGLContext/opengl_ColorBufferReaderWithBufferStorage.cpp b/src/Graphics/OpenGLContext/opengl_ColorBufferReaderWithBufferStorage.cpp index 3db11047..f85d98a9 100644 --- a/src/Graphics/OpenGLContext/opengl_ColorBufferReaderWithBufferStorage.cpp +++ b/src/Graphics/OpenGLContext/opengl_ColorBufferReaderWithBufferStorage.cpp @@ -41,25 +41,16 @@ void ColorBufferReaderWithBufferStorage::_destroyBuffers() m_PBO[index] = 0; } -u8 * ColorBufferReaderWithBufferStorage::readPixels(s32 _x0, s32 _y0, u32 _width, u32 _height, u32 _size, bool _sync) +const u8 * ColorBufferReaderWithBufferStorage::_readPixels(const ReadColorBufferParams& _params, u32& _heightOffset, + u32& _stride) { - const FramebufferTextureFormats & fbTexFormat = gfxContext.getFramebufferTextureFormats(); - GLenum colorFormat, colorType, colorFormatBytes; - if (_size > G_IM_SIZ_8b) { - colorFormat = GLenum(fbTexFormat.colorFormat); - colorType = GLenum(fbTexFormat.colorType); - colorFormatBytes = GLenum(fbTexFormat.colorFormatBytes); - } - else { - colorFormat = GLenum(fbTexFormat.monochromeFormat); - colorType = GLenum(fbTexFormat.monochromeType); - colorFormatBytes = GLenum(fbTexFormat.monochromeFormatBytes); - } + GLenum format = GLenum(_params.colorFormat); + GLenum type = GLenum(_params.colorType); m_bindBuffer->bind(Parameter(GL_PIXEL_PACK_BUFFER), ObjectHandle(m_PBO[m_curIndex])); - glReadPixels(_x0, _y0, m_pTexture->realWidth, _height, colorFormat, colorType, 0); + glReadPixels(_params.x0, _params.y0, m_pTexture->realWidth, _params.height, format, type, 0); - if (!_sync) { + if (!_params.sync) { //Setup a fence sync object so that we know when glReadPixels completes m_fence[m_curIndex] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); m_curIndex = (m_curIndex + 1) % _numPBO; @@ -72,19 +63,10 @@ u8 * ColorBufferReaderWithBufferStorage::readPixels(s32 _x0, s32 _y0, u32 _width glFinish(); } - GLubyte* pixelData = reinterpret_cast(m_PBOData[m_curIndex]); - if (pixelData == nullptr) - return nullptr; + _heightOffset = 0; + _stride = m_pTexture->realWidth; - int widthBytes = _width * colorFormatBytes; - int strideBytes = m_pTexture->realWidth * colorFormatBytes; - - GLubyte* pixelDataAlloc = m_pixelData.data(); - for (unsigned int lnIndex = 0; lnIndex < _height; ++lnIndex) { - memcpy(pixelDataAlloc + lnIndex*widthBytes, pixelData + (lnIndex*strideBytes), widthBytes); - } - - return pixelDataAlloc; + return reinterpret_cast(m_PBOData[m_curIndex]); } void ColorBufferReaderWithBufferStorage::cleanUp() diff --git a/src/Graphics/OpenGLContext/opengl_ColorBufferReaderWithBufferStorage.h b/src/Graphics/OpenGLContext/opengl_ColorBufferReaderWithBufferStorage.h index cfca6d2e..5e144393 100644 --- a/src/Graphics/OpenGLContext/opengl_ColorBufferReaderWithBufferStorage.h +++ b/src/Graphics/OpenGLContext/opengl_ColorBufferReaderWithBufferStorage.h @@ -2,6 +2,7 @@ #include #include "opengl_CachedFunctions.h" +#include namespace opengl { @@ -13,7 +14,8 @@ namespace opengl { CachedBindBuffer * _bindBuffer); virtual ~ColorBufferReaderWithBufferStorage(); - u8 * readPixels(s32 _x0, s32 _y0, u32 _width, u32 _height, u32 _size, bool _sync) override; + const u8 * _readPixels(const ReadColorBufferParams& _params, u32& _heightOffset, u32& _stride) override; + void cleanUp() override; private: diff --git a/src/Graphics/OpenGLContext/opengl_ColorBufferReaderWithEGLImage.cpp b/src/Graphics/OpenGLContext/opengl_ColorBufferReaderWithEGLImage.cpp index 15400bb5..0062a6c0 100644 --- a/src/Graphics/OpenGLContext/opengl_ColorBufferReaderWithEGLImage.cpp +++ b/src/Graphics/OpenGLContext/opengl_ColorBufferReaderWithEGLImage.cpp @@ -11,6 +11,7 @@ ColorBufferReaderWithEGLImage::ColorBufferReaderWithEGLImage(CachedTexture *_pTe : graphics::ColorBufferReader(_pTexture) , m_bindTexture(_bindTexture) , m_image(0) + , m_bufferLocked(false) { m_glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)eglGetProcAddress("glEGLImageTargetTexture2DOES"); _initBuffers(); @@ -35,48 +36,43 @@ void ColorBufferReaderWithEGLImage::_initBuffers() } } -u8 * ColorBufferReaderWithEGLImage::readPixels(s32 _x0, s32 _y0, u32 _width, u32 _height, u32 _size, bool _sync) + +const u8 * ColorBufferReaderWithEGLImage::_readPixels(const ReadColorBufferParams& _params, u32& _heightOffset, + u32& _stride) { - const graphics::FramebufferTextureFormats & fbTexFormat = gfxContext.getFramebufferTextureFormats(); - GLenum colorFormat, colorType, colorFormatBytes; - if (_size > G_IM_SIZ_8b) { - colorFormat = GLenum(fbTexFormat.colorFormat); - colorType = GLenum(fbTexFormat.colorType); - colorFormatBytes = GLenum(fbTexFormat.colorFormatBytes); - } - else { - colorFormat = GLenum(fbTexFormat.monochromeFormat); - colorType = GLenum(fbTexFormat.monochromeType); - colorFormatBytes = GLenum(fbTexFormat.monochromeFormatBytes); - } + GLenum format = GLenum(_params.colorFormat); + GLenum type = GLenum(_params.colorType); - u8* pixelData = m_pixelData.data(); + void* gpuData = nullptr; + const u8* returnData = nullptr; - if (!_sync) { - void* ptr; + if (!_params.sync) { m_bindTexture->bind(graphics::Parameter(0), graphics::Parameter(GL_TEXTURE_2D), m_pTexture->name); m_glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, m_image); m_bindTexture->bind(graphics::Parameter(0), graphics::Parameter(GL_TEXTURE_2D), ObjectHandle()); - int widthBytes = _width*colorFormatBytes; - int strideBytes = m_pTexture->realWidth * colorFormatBytes; - m_window.lock(GRALLOC_USAGE_SW_READ_OFTEN, &ptr); + m_window.lock(GRALLOC_USAGE_SW_READ_OFTEN, &gpuData); + m_bufferLocked = true; + _heightOffset = static_cast(_params.y0); + _stride = m_pTexture->realWidth; - for (unsigned int lnIndex = 0; lnIndex < _height; ++lnIndex) { - memcpy(pixelData + lnIndex*widthBytes, reinterpret_cast(ptr) + ((lnIndex + _y0)*strideBytes), widthBytes); - } - - m_window.unlock(); } else { - glReadPixels(_x0, _y0, _width, _height, colorFormat, colorType, pixelData); + gpuData = m_pixelData.data(); + glReadPixels(_params.x0, _params.y0, _params.width, _params.height, format, type, gpuData); + _heightOffset = 0; + _stride = 0; } - return pixelData; + return reinterpret_cast(gpuData); } void ColorBufferReaderWithEGLImage::cleanUp() { + if (m_bufferLocked) { + m_window.unlock(); + m_bufferLocked = false; + } } #endif // EGL diff --git a/src/Graphics/OpenGLContext/opengl_ColorBufferReaderWithEGLImage.h b/src/Graphics/OpenGLContext/opengl_ColorBufferReaderWithEGLImage.h index f7c5d6ef..761c8277 100644 --- a/src/Graphics/OpenGLContext/opengl_ColorBufferReaderWithEGLImage.h +++ b/src/Graphics/OpenGLContext/opengl_ColorBufferReaderWithEGLImage.h @@ -19,7 +19,8 @@ public: CachedBindTexture * _bindTexture); ~ColorBufferReaderWithEGLImage(); - u8 * readPixels(s32 _x0, s32 _y0, u32 _width, u32 _height, u32 _size, bool _sync) override; + const u8 * _readPixels(const ReadColorBufferParams& _params, u32& _heightOffset, u32& _stride) override; + void cleanUp() override; private: @@ -29,6 +30,7 @@ private: GraphicBuffer m_window{}; EGLImageKHR m_image; PFNGLEGLIMAGETARGETTEXTURE2DOESPROC m_glEGLImageTargetTexture2DOES; + bool m_bufferLocked; }; } diff --git a/src/Graphics/OpenGLContext/opengl_ColorBufferReaderWithPixelBuffer.cpp b/src/Graphics/OpenGLContext/opengl_ColorBufferReaderWithPixelBuffer.cpp index a96150a9..3ba380d0 100644 --- a/src/Graphics/OpenGLContext/opengl_ColorBufferReaderWithPixelBuffer.cpp +++ b/src/Graphics/OpenGLContext/opengl_ColorBufferReaderWithPixelBuffer.cpp @@ -39,45 +39,30 @@ void ColorBufferReaderWithPixelBuffer::_initBuffers() m_bindBuffer->bind(Parameter(GL_PIXEL_PACK_BUFFER), ObjectHandle::null); } -u8 * ColorBufferReaderWithPixelBuffer::readPixels(s32 _x0, s32 _y0, u32 _width, u32 _height, u32 _size, bool _sync) +const u8 * ColorBufferReaderWithPixelBuffer::_readPixels(const ReadColorBufferParams& _params, u32& _heightOffset, + u32& _stride) { - const graphics::FramebufferTextureFormats & fbTexFormat = gfxContext.getFramebufferTextureFormats(); - GLenum colorFormat, colorType, colorFormatBytes; - if (_size > G_IM_SIZ_8b) { - colorFormat = GLenum(fbTexFormat.colorFormat); - colorType = GLenum(fbTexFormat.colorType); - colorFormatBytes = GLenum(fbTexFormat.colorFormatBytes); - } else { - colorFormat = GLenum(fbTexFormat.monochromeFormat); - colorType = GLenum(fbTexFormat.monochromeType); - colorFormatBytes = GLenum(fbTexFormat.monochromeFormatBytes); - } + GLenum format = GLenum(_params.colorFormat); + GLenum type = GLenum(_params.colorType); // If Sync, read pixels from the buffer, copy them to RDRAM. // If not Sync, read pixels from the buffer, copy pixels from the previous buffer to RDRAM. - if (!_sync) { + if (!_params.sync) { m_curIndex ^= 1; const u32 nextIndex = m_curIndex ^ 1; m_bindBuffer->bind(Parameter(GL_PIXEL_PACK_BUFFER), ObjectHandle(m_PBO[m_curIndex])); - glReadPixels(_x0, _y0, m_pTexture->realWidth, _height, colorFormat, colorType, 0); + glReadPixels(_params.x0, _params.y0, m_pTexture->realWidth, _params.height, format, type, 0); m_bindBuffer->bind(Parameter(GL_PIXEL_PACK_BUFFER), ObjectHandle(m_PBO[nextIndex])); } else { m_bindBuffer->bind(Parameter(GL_PIXEL_PACK_BUFFER), ObjectHandle(m_PBO[_numPBO -1])); - glReadPixels(_x0, _y0, m_pTexture->realWidth, _height, colorFormat, colorType, 0); + glReadPixels(_params.x0, _params.y0, m_pTexture->realWidth, _params.height, format, type, 0); } - GLubyte* pixelData = (GLubyte*)glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, m_pTexture->realWidth * _height * colorFormatBytes, GL_MAP_READ_BIT); - if (pixelData == nullptr) - return nullptr; + _heightOffset = 0; + _stride = m_pTexture->realWidth; - int widthBytes = _width*colorFormatBytes; - int strideBytes = m_pTexture->realWidth * colorFormatBytes; - - u8 * pixelDataAlloc = m_pixelData.data(); - for (unsigned int lnIndex = 0; lnIndex < _height; ++lnIndex) { - memcpy(pixelDataAlloc + lnIndex*widthBytes, pixelData + (lnIndex*strideBytes), widthBytes); - } - return pixelDataAlloc; + return reinterpret_cast(glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, + m_pTexture->realWidth * _params.height * _params.colorFormatBytes, GL_MAP_READ_BIT)); } void ColorBufferReaderWithPixelBuffer::cleanUp() diff --git a/src/Graphics/OpenGLContext/opengl_ColorBufferReaderWithPixelBuffer.h b/src/Graphics/OpenGLContext/opengl_ColorBufferReaderWithPixelBuffer.h index dc67c269..50929162 100644 --- a/src/Graphics/OpenGLContext/opengl_ColorBufferReaderWithPixelBuffer.h +++ b/src/Graphics/OpenGLContext/opengl_ColorBufferReaderWithPixelBuffer.h @@ -12,7 +12,7 @@ public: CachedBindBuffer * _bindBuffer); ~ColorBufferReaderWithPixelBuffer(); - u8 * readPixels(s32 _x0, s32 _y0, u32 _width, u32 _height, u32 _size, bool _sync) override; + const u8 * _readPixels(const ReadColorBufferParams& _params, u32& _heightOffset, u32& _stride) override; void cleanUp() override; private: diff --git a/src/Graphics/OpenGLContext/opengl_ColorBufferReaderWithReadPixels.cpp b/src/Graphics/OpenGLContext/opengl_ColorBufferReaderWithReadPixels.cpp index f4df5816..8aace1f3 100644 --- a/src/Graphics/OpenGLContext/opengl_ColorBufferReaderWithReadPixels.cpp +++ b/src/Graphics/OpenGLContext/opengl_ColorBufferReaderWithReadPixels.cpp @@ -11,31 +11,20 @@ ColorBufferReaderWithReadPixels::ColorBufferReaderWithReadPixels(CachedTexture * } -u8 * ColorBufferReaderWithReadPixels::readPixels(s32 _x0, s32 _y0, u32 _width, u32 _height, u32 _size, bool _sync) +const u8 * ColorBufferReaderWithReadPixels::_readPixels(const ReadColorBufferParams& _params, u32& _heightOffset, + u32& _stride) { - const graphics::FramebufferTextureFormats & fbTexFormat = gfxContext.getFramebufferTextureFormats(); - GLenum colorFormat, colorType, colorFormatBytes; - if (_size > G_IM_SIZ_8b) { - colorFormat = GLenum(fbTexFormat.colorFormat); - colorType = GLenum(fbTexFormat.colorType); - colorFormatBytes = GLenum(fbTexFormat.colorFormatBytes); - } else { - colorFormat = GLenum(fbTexFormat.monochromeFormat); - colorType = GLenum(fbTexFormat.monochromeType); - colorFormatBytes = GLenum(fbTexFormat.monochromeFormatBytes); - } + GLenum format = GLenum(_params.colorFormat); + GLenum type = GLenum(_params.colorType); // No async pixel buffer copies are supported in this class, this is a last resort fallback - auto pixelData = std::unique_ptr(new GLubyte[m_pTexture->realWidth * _height * colorFormatBytes]) ; - glReadPixels(_x0, _y0, m_pTexture->realWidth, _height, colorFormat, colorType, pixelData.get()); + u8* gpuData = m_pixelData.data(); + glReadPixels(_params.x0, _params.y0, m_pTexture->realWidth, _params.height, format, type, gpuData); - int widthBytes = _width*colorFormatBytes; - int strideBytes = m_pTexture->realWidth * colorFormatBytes; + _heightOffset = 0; + _stride = m_pTexture->realWidth; - for (unsigned int lnIndex = 0; lnIndex < _height; ++lnIndex) { - std::copy_n(pixelData.get() + (lnIndex*strideBytes), widthBytes, m_pixelData.data() + lnIndex*widthBytes); - } - return m_pixelData.data(); + return gpuData; } void ColorBufferReaderWithReadPixels::cleanUp() diff --git a/src/Graphics/OpenGLContext/opengl_ColorBufferReaderWithReadPixels.h b/src/Graphics/OpenGLContext/opengl_ColorBufferReaderWithReadPixels.h index 841176ab..9e5fcc8d 100644 --- a/src/Graphics/OpenGLContext/opengl_ColorBufferReaderWithReadPixels.h +++ b/src/Graphics/OpenGLContext/opengl_ColorBufferReaderWithReadPixels.h @@ -11,7 +11,7 @@ public: ColorBufferReaderWithReadPixels(CachedTexture * _pTexture); ~ColorBufferReaderWithReadPixels() = default; - u8 * readPixels(s32 _x0, s32 _y0, u32 _width, u32 _height, u32 _size, bool _sync) override; + const u8 * _readPixels(const ReadColorBufferParams& _params, u32& _heightOffset, u32& _stride) override; void cleanUp() override; }; diff --git a/src/mupen64plus-video-gliden64.mk b/src/mupen64plus-video-gliden64.mk index 77cdd4a1..6ab06ec8 100644 --- a/src/mupen64plus-video-gliden64.mk +++ b/src/mupen64plus-video-gliden64.mk @@ -78,6 +78,7 @@ MY_LOCAL_SRC_FILES := \ $(SRCDIR)/BufferCopy/DepthBufferToRDRAM.cpp \ $(SRCDIR)/BufferCopy/RDRAMtoColorBuffer.cpp \ $(SRCDIR)/Graphics/Context.cpp \ + $(SRCDIR)/Graphics/ColorBufferReader.cpp \ $(SRCDIR)/Graphics/CombinerProgram.cpp \ $(SRCDIR)/Graphics/ObjectHandle.cpp \ $(SRCDIR)/Graphics/OpenGLContext/GLFunctions.cpp \