From eabcb22623494b35745c4f8f3c0255fc8c59c69b Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Sun, 19 Feb 2017 11:02:24 +0100 Subject: [PATCH 1/5] Refactor away SetImageData --- GPU/Software/SoftGpu.cpp | 130 +++++++++++++++------------- ext/native/gfx_es2/draw_text.cpp | 8 +- ext/native/thin3d/thin3d.h | 2 - ext/native/thin3d/thin3d_d3d11.cpp | 4 - ext/native/thin3d/thin3d_d3d9.cpp | 4 +- ext/native/thin3d/thin3d_gl.cpp | 76 ++++++++-------- ext/native/thin3d/thin3d_vulkan.cpp | 4 +- 7 files changed, 117 insertions(+), 111 deletions(-) diff --git a/GPU/Software/SoftGpu.cpp b/GPU/Software/SoftGpu.cpp index 776873afc0..6cbf267782 100644 --- a/GPU/Software/SoftGpu.cpp +++ b/GPU/Software/SoftGpu.cpp @@ -58,15 +58,7 @@ SoftGPU::SoftGPU(GraphicsContext *gfxCtx, Draw::DrawContext *draw) : GPUCommon(gfxCtx, draw) { using namespace Draw; - TextureDesc desc{}; - desc.type = TextureType::LINEAR2D; - desc.format = DataFormat::R8G8B8A8_UNORM; - desc.width = 480; - desc.height = 272; - desc.depth = 1; - desc.mipLevels = 1; - fbTex = draw_->CreateTexture(desc); - + fbTex = nullptr; InputLayoutDesc inputDesc = { { { sizeof(Vertex), false }, @@ -124,9 +116,10 @@ SoftGPU::~SoftGPU() { texColor->Release(); texColor = nullptr; - fbTex->Release(); - fbTex = nullptr; - + if (fbTex) { + fbTex->Release(); + fbTex = nullptr; + } vdata->Release(); vdata = nullptr; idata->Release(); @@ -147,32 +140,38 @@ void SoftGPU::SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat for // Copies RGBA8 data from RAM to the currently bound render target. void SoftGPU::CopyToCurrentFboFromDisplayRam(int srcwidth, int srcheight) { - using namespace Draw; - if (!draw_) return; float dstwidth = (float)PSP_CoreParameter().pixelWidth; float dstheight = (float)PSP_CoreParameter().pixelHeight; - Viewport viewport = {0.0f, 0.0f, dstwidth, dstheight, 0.0f, 1.0f}; + Draw::Viewport viewport = {0.0f, 0.0f, dstwidth, dstheight, 0.0f, 1.0f}; draw_->SetViewports(1, &viewport); - SamplerState *sampler; - if (g_Config.iBufFilter == SCALE_NEAREST) { - sampler = samplerNearest; - } else { - sampler = samplerLinear; - } draw_->SetScissorRect(0, 0, dstwidth, dstheight); float u0 = 0.0f; float u1; + + if (fbTex) { + fbTex->Release(); + fbTex = nullptr; + } + + Draw::TextureDesc desc{}; + desc.type = Draw::TextureType::LINEAR2D; + desc.format = Draw::DataFormat::R8G8B8A8_UNORM; + desc.depth = 1; + desc.mipLevels = 1; bool hasImage = true; if (!Memory::IsValidAddress(displayFramebuf_)) { hasImage = false; u1 = 1.0f; } else if (displayFormat_ == GE_FORMAT_8888) { u8 *data = Memory::GetPointer(displayFramebuf_); - fbTex->SetImageData(0, 0, 0, displayStride_, srcheight, 1, 0, displayStride_ * 4, data); + desc.width = displayStride_; + desc.height = srcheight; + desc.initData.push_back(data); + desc.format = Draw::DataFormat::R8G8B8A8_UNORM; u1 = (float)srcwidth / displayStride_; } else { // TODO: This should probably be converted in a shader instead.. @@ -201,9 +200,16 @@ void SoftGPU::CopyToCurrentFboFromDisplayRam(int srcwidth, int srcheight) { } } - fbTex->SetImageData(0, 0, 0, srcwidth, srcheight, 1, 0, srcwidth * 4, (const uint8_t *)&fbTexBuffer[0]); + desc.width = srcwidth; + desc.height = srcheight; u1 = 1.0f; } + if (!hasImage) { + draw_->Clear(Draw::FB_COLOR_BIT, 0, 0, 0); + return; + } + + fbTex = draw_->CreateTexture(desc); float x, y, w, h; CenterDisplayOutputRect(&x, &y, &w, &h, 480.0f, 272.0f, dstwidth, dstheight, ROTATION_LOCKED_HORIZONTAL); @@ -224,46 +230,48 @@ void SoftGPU::CopyToCurrentFboFromDisplayRam(int srcwidth, int srcheight) { x2 -= 1.0f; y2 -= 1.0f; - if (hasImage) { - float v0 = 1.0f; - float v1 = 0.0f; + float v0 = 1.0f; + float v1 = 0.0f; - if (GetGPUBackend() == GPUBackend::VULKAN) { - std::swap(v0, v1); - } - - draw_->BindSamplerStates(0, 1, &sampler); - - const Vertex verts[4] = { - { x, y, 0, u0, v0, 0xFFFFFFFF }, // TL - { x, y2, 0, u0, v1, 0xFFFFFFFF }, // BL - { x2, y2, 0, u1, v1, 0xFFFFFFFF }, // BR - { x2, y, 0, u1, v0, 0xFFFFFFFF }, // TR - }; - draw_->UpdateBuffer(vdata, (const uint8_t *)verts, 0, sizeof(verts), Draw::UPDATE_DISCARD); - - int indexes[] = { 0, 1, 2, 0, 2, 3 }; - draw_->UpdateBuffer(idata, (const uint8_t *)indexes, 0, sizeof(indexes), Draw::UPDATE_DISCARD); - - draw_->BindTexture(0, fbTex); - - static const float identity4x4[16] = { - 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f, - }; - - VsTexColUB ub{}; - memcpy(ub.WorldViewProj, identity4x4, sizeof(float) * 16); - draw_->BindPipeline(texColor); - draw_->UpdateDynamicUniformBuffer(&ub, sizeof(ub)); - draw_->BindVertexBuffers(0, 1, &vdata, nullptr); - draw_->BindIndexBuffer(idata, 0); - draw_->DrawIndexed(6, 0); - } else { - draw_->Clear(Draw::FB_COLOR_BIT, 0, 0, 0); + if (GetGPUBackend() == GPUBackend::VULKAN) { + std::swap(v0, v1); } + + Draw::SamplerState *sampler; + if (g_Config.iBufFilter == SCALE_NEAREST) { + sampler = samplerNearest; + } else { + sampler = samplerLinear; + } + draw_->BindSamplerStates(0, 1, &sampler); + + const Vertex verts[4] = { + { x, y, 0, u0, v0, 0xFFFFFFFF }, // TL + { x, y2, 0, u0, v1, 0xFFFFFFFF }, // BL + { x2, y2, 0, u1, v1, 0xFFFFFFFF }, // BR + { x2, y, 0, u1, v0, 0xFFFFFFFF }, // TR + }; + draw_->UpdateBuffer(vdata, (const uint8_t *)verts, 0, sizeof(verts), Draw::UPDATE_DISCARD); + + int indexes[] = { 0, 1, 2, 0, 2, 3 }; + draw_->UpdateBuffer(idata, (const uint8_t *)indexes, 0, sizeof(indexes), Draw::UPDATE_DISCARD); + + draw_->BindTexture(0, fbTex); + + static const float identity4x4[16] = { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f, + }; + + Draw::VsTexColUB ub{}; + memcpy(ub.WorldViewProj, identity4x4, sizeof(float) * 16); + draw_->BindPipeline(texColor); + draw_->UpdateDynamicUniformBuffer(&ub, sizeof(ub)); + draw_->BindVertexBuffers(0, 1, &vdata, nullptr); + draw_->BindIndexBuffer(idata, 0); + draw_->DrawIndexed(6, 0); } void SoftGPU::CopyDisplayToOutput() diff --git a/ext/native/gfx_es2/draw_text.cpp b/ext/native/gfx_es2/draw_text.cpp index 7454364f8e..54e67246bd 100644 --- a/ext/native/gfx_es2/draw_text.cpp +++ b/ext/native/gfx_es2/draw_text.cpp @@ -476,12 +476,11 @@ void TextDrawer::DrawString(DrawBuffer &target, const char *str, float x, float TextureDesc desc{}; desc.type = TextureType::LINEAR2D; - desc.format = Draw::DataFormat::R4G4B4A4_UNORM_PACK16; + desc.format = Draw::DataFormat::B4G4R4A4_UNORM_PACK16; desc.width = entry->bmWidth; desc.height = entry->bmHeight; desc.depth = 1; desc.mipLevels = 1; - entry->texture = draw_->CreateTexture(desc); uint16_t *bitmapData = new uint16_t[entry->bmWidth * entry->bmHeight]; for (int x = 0; x < entry->bmWidth; x++) { @@ -489,10 +488,9 @@ void TextDrawer::DrawString(DrawBuffer &target, const char *str, float x, float bitmapData[entry->bmWidth * y + x] = 0xfff0 | image.pixel(x, y) >> 28; } } - entry->texture->SetImageData(0, 0, 0, entry->bmWidth, entry->bmHeight, 1, 0, entry->bmWidth * 2, (const uint8_t *)bitmapData); - + desc.initData.push_back(bitmapData); + entry->texture = draw_->CreateTexture(desc); delete [] bitmapData; - cache_[entryHash] = std::unique_ptr(entry); } float w = entry->bmWidth * fontScaleX_; diff --git a/ext/native/thin3d/thin3d.h b/ext/native/thin3d/thin3d.h index 4676f880ac..ceac009c5a 100644 --- a/ext/native/thin3d/thin3d.h +++ b/ext/native/thin3d/thin3d.h @@ -406,8 +406,6 @@ public: class Texture : public RefCountedObject { public: - virtual void SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data) = 0; - int Width() { return width_; } int Height() { return height_; } int Depth() { return depth_; } diff --git a/ext/native/thin3d/thin3d_d3d11.cpp b/ext/native/thin3d/thin3d_d3d11.cpp index 480fdcaf40..d10383a6fd 100644 --- a/ext/native/thin3d/thin3d_d3d11.cpp +++ b/ext/native/thin3d/thin3d_d3d11.cpp @@ -647,10 +647,6 @@ public: view->Release(); } - void SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data) { - ELOG("SetImageData not supported, create a new texture instead"); - } - ID3D11Texture2D *tex = nullptr; ID3D11ShaderResourceView *view = nullptr; }; diff --git a/ext/native/thin3d/thin3d_d3d9.cpp b/ext/native/thin3d/thin3d_d3d9.cpp index a9785acf2d..d84e841e31 100644 --- a/ext/native/thin3d/thin3d_d3d9.cpp +++ b/ext/native/thin3d/thin3d_d3d9.cpp @@ -297,10 +297,10 @@ class D3D9Texture : public Texture { public: D3D9Texture(LPDIRECT3DDEVICE9 device, LPDIRECT3DDEVICE9EX deviceEx, const TextureDesc &desc); ~D3D9Texture(); - void SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data) override; void SetToSampler(LPDIRECT3DDEVICE9 device, int sampler); private: + void SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data); bool Create(const TextureDesc &desc); LPDIRECT3DDEVICE9 device_; LPDIRECT3DDEVICE9EX deviceEx_; @@ -364,7 +364,7 @@ bool D3D9Texture::Create(const TextureDesc &desc) { if (desc.initData.size()) { for (int i = 0; i < desc.initData.size(); i++) { - this->SetImageData(0, 0, 0, width_, height_, depth_, i, 0, desc.initData[i]); + SetImageData(0, 0, 0, width_, height_, depth_, i, 0, desc.initData[i]); } } return true; diff --git a/ext/native/thin3d/thin3d_gl.cpp b/ext/native/thin3d/thin3d_gl.cpp index 6c34d00b47..bc049a6ee6 100644 --- a/ext/native/thin3d/thin3d_gl.cpp +++ b/ext/native/thin3d/thin3d_gl.cpp @@ -656,42 +656,9 @@ inline bool isPowerOf2(int n) { class OpenGLTexture : public Texture { public: - OpenGLTexture(const TextureDesc &desc) : tex_(0), target_(TypeToTarget(desc.type)), format_(desc.format), mipLevels_(desc.mipLevels) { - generatedMips_ = false; - canWrap_ = true; - width_ = desc.width; - height_ = desc.height; - depth_ = desc.depth; - canWrap_ = !isPowerOf2(width_) || !isPowerOf2(height_); + OpenGLTexture(const TextureDesc &desc); + ~OpenGLTexture(); - glGenTextures(1, &tex_); - - if (!desc.initData.size()) - return; - - int level = 0; - for (auto data : desc.initData) { - SetImageData(0, 0, 0, width_, height_, depth_, level, 0, data); - width_ = (width_ + 1) /2; - height_ = (height_ + 1) /2; - level++; - } - if (desc.initData.size() < desc.mipLevels) - AutoGenMipmaps(); - } - ~OpenGLTexture() { - Destroy(); - } - - void Destroy() { - if (tex_) { - glDeleteTextures(1, &tex_); - tex_ = 0; - generatedMips_ = false; - } - } - - void SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data) override; void AutoGenMipmaps(); bool HasMips() { @@ -706,6 +673,8 @@ public: } private: + void SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data); + GLuint tex_; GLuint target_; @@ -715,6 +684,43 @@ private: bool canWrap_; }; +OpenGLTexture::OpenGLTexture(const TextureDesc &desc) : tex_(0), target_(TypeToTarget(desc.type)), format_(desc.format), mipLevels_(desc.mipLevels) { + generatedMips_ = false; + canWrap_ = true; + width_ = desc.width; + height_ = desc.height; + depth_ = desc.depth; + canWrap_ = !isPowerOf2(width_) || !isPowerOf2(height_); + + glGenTextures(1, &tex_); + + if (!desc.initData.size()) + return; + + int level = 0; + for (auto data : desc.initData) { + SetImageData(0, 0, 0, width_, height_, depth_, level, 0, data); + width_ = (width_ + 1) / 2; + height_ = (height_ + 1) / 2; + level++; + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, level - 1); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, level > 1 ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + if (desc.initData.size() < desc.mipLevels) + AutoGenMipmaps(); +} + +OpenGLTexture::~OpenGLTexture() { + if (tex_) { + glDeleteTextures(1, &tex_); + tex_ = 0; + generatedMips_ = false; + } +} + Texture *OpenGLContext::CreateTexture(const TextureDesc &desc) { return new OpenGLTexture(desc); } diff --git a/ext/native/thin3d/thin3d_vulkan.cpp b/ext/native/thin3d/thin3d_vulkan.cpp index 8dc545193b..07da6fc8dd 100644 --- a/ext/native/thin3d/thin3d_vulkan.cpp +++ b/ext/native/thin3d/thin3d_vulkan.cpp @@ -597,11 +597,11 @@ public: Destroy(); } - void SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data) override; - VkImageView GetImageView() { return vkTex_->GetImageView(); } private: + void SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data); + bool Create(const TextureDesc &desc) { format_ = desc.format; mipLevels_ = desc.mipLevels; From b35493c72687fb35628fc3d097449e99a3816a10 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Sun, 19 Feb 2017 11:09:28 +0100 Subject: [PATCH 2/5] Fix minor issue in gamesettings --- UI/GameSettingsScreen.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 5b8c95e4f4..31ff22f327 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -412,6 +412,7 @@ void GameSettingsScreen::CreateViews() { CheckBox *softwareGPU = graphicsSettings->Add(new CheckBox(&g_Config.bSoftwareRendering, gr->T("Software Rendering", "Software Rendering (experimental)"))); softwareGPU->OnClick.Add([=](EventParams &e) { settingInfo_->Show(gr->T("SoftGPU Tip", "Currently VERY slow"), e.v); + bloomHackEnable_ = !g_Config.bSoftwareRendering && (g_Config.iInternalResolution != 1); return UI::EVENT_CONTINUE; }); softwareGPU->OnClick.Handle(this, &GameSettingsScreen::OnSoftwareRendering); From 1c33ac8dc1232e68a22a6a7dc61f504e81126523 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Sun, 19 Feb 2017 11:09:42 +0100 Subject: [PATCH 3/5] Fix even more confusion around 4-bit RGBA texture formats --- ext/native/thin3d/thin3d_gl.cpp | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/ext/native/thin3d/thin3d_gl.cpp b/ext/native/thin3d/thin3d_gl.cpp index bc049a6ee6..091c190cfd 100644 --- a/ext/native/thin3d/thin3d_gl.cpp +++ b/ext/native/thin3d/thin3d_gl.cpp @@ -705,7 +705,13 @@ OpenGLTexture::OpenGLTexture(const TextureDesc &desc) : tex_(0), target_(TypeToT level++; } +#ifdef USING_GLES2 + if (gl_extensions.GLES3) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, level - 1); + } +#else glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, level - 1); +#endif glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, level > 1 ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); @@ -753,12 +759,11 @@ void OpenGLTexture::SetImageData(int x, int y, int z, int width, int height, int format = GL_RGBA; type = GL_UNSIGNED_BYTE; break; - case DataFormat::R4G4B4A4_UNORM_PACK16: + case DataFormat::B4G4R4A4_UNORM_PACK16: internalFormat = GL_RGBA; format = GL_RGBA; type = GL_UNSIGNED_SHORT_4_4_4_4; break; - #ifndef USING_GLES2 case DataFormat::A4B4G4R4_UNORM_PACK16: internalFormat = GL_RGBA; @@ -766,7 +771,6 @@ void OpenGLTexture::SetImageData(int x, int y, int z, int width, int height, int type = GL_UNSIGNED_SHORT_4_4_4_4_REV; break; #endif - default: ELOG("Thin3d GL: Unsupported texture format %d", (int)format_); return; @@ -1645,12 +1649,14 @@ uint32_t OpenGLContext::GetDataFormatSupport(DataFormat fmt) const { switch (fmt) { case DataFormat::B8G8R8A8_UNORM: return FMT_RENDERTARGET | FMT_TEXTURE; - case DataFormat::R4G4B4A4_UNORM_PACK16: - return FMT_RENDERTARGET | FMT_TEXTURE; case DataFormat::B4G4R4A4_UNORM_PACK16: - return 0; // native support + return FMT_RENDERTARGET | FMT_TEXTURE; // native support case DataFormat::A4B4G4R4_UNORM_PACK16: - return 0; // Can support this if _REV formats are supported. +#ifndef USING_GLES2 + // Can support this if _REV formats are supported. + return FMT_TEXTURE; +#endif + return 0; case DataFormat::R8G8B8A8_UNORM: return FMT_RENDERTARGET | FMT_TEXTURE | FMT_INPUTLAYOUT; From 387ad7e4d65e8eb136389f61b523dc361523d2f2 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Sun, 19 Feb 2017 11:22:23 +0100 Subject: [PATCH 4/5] OpenGL DrawContext texture handling cleanup, fixing some bugs. --- GPU/D3D11/FramebufferManagerD3D11.h | 2 +- GPU/Vulkan/FramebufferVulkan.h | 4 +- ext/native/thin3d/thin3d.h | 6 +- ext/native/thin3d/thin3d_gl.cpp | 173 +++++++++++++++------------- 4 files changed, 96 insertions(+), 89 deletions(-) diff --git a/GPU/D3D11/FramebufferManagerD3D11.h b/GPU/D3D11/FramebufferManagerD3D11.h index 5cf4afe8a3..469bad59cb 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.h +++ b/GPU/D3D11/FramebufferManagerD3D11.h @@ -82,7 +82,7 @@ public: } protected: - void SetViewport2D(int x, int y, int w, int h); + void SetViewport2D(int x, int y, int w, int h) override; void DisableState() override; void ClearBuffer(bool keepState = false) override; void FlushBeforeCopy() override; diff --git a/GPU/Vulkan/FramebufferVulkan.h b/GPU/Vulkan/FramebufferVulkan.h index b424adccb9..f8603bccb3 100644 --- a/GPU/Vulkan/FramebufferVulkan.h +++ b/GPU/Vulkan/FramebufferVulkan.h @@ -122,7 +122,7 @@ public: protected: void Bind2DShader() override; void BindPostShader(const PostShaderUniforms &uniforms) override; - void SetViewport2D(int x, int y, int w, int h); + void SetViewport2D(int x, int y, int w, int h) override; void DisableState() override {} void ClearBuffer(bool keepState = false) override; void FlushBeforeCopy() override; @@ -135,7 +135,7 @@ protected: private: // The returned texture does not need to be free'd, might be returned from a pool (currently single entry) - void MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height); + void MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height) override; void DoNotifyDraw(); VkCommandBuffer AllocFrameCommandBuffer(); diff --git a/ext/native/thin3d/thin3d.h b/ext/native/thin3d/thin3d.h index ceac009c5a..b5366abd52 100644 --- a/ext/native/thin3d/thin3d.h +++ b/ext/native/thin3d/thin3d.h @@ -111,8 +111,8 @@ enum class StencilOp { }; enum class TextureFilter : int { - NEAREST, - LINEAR, + NEAREST = 0, + LINEAR = 1, }; enum BufferUsageFlag : int { @@ -273,7 +273,7 @@ enum { }; enum class TextureAddressMode { - REPEAT, + REPEAT = 0, REPEAT_MIRROR, CLAMP_TO_EDGE, CLAMP_TO_BORDER, diff --git a/ext/native/thin3d/thin3d_gl.cpp b/ext/native/thin3d/thin3d_gl.cpp index 091c190cfd..8d7f514783 100644 --- a/ext/native/thin3d/thin3d_gl.cpp +++ b/ext/native/thin3d/thin3d_gl.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include "base/logging.h" @@ -77,7 +78,7 @@ static const unsigned short texWrapToGL[] = { #if !defined(USING_GLES2) GL_CLAMP_TO_BORDER, #else - GL_REPEAT, + GL_CLAMP_TO_EDGE, #endif }; @@ -193,30 +194,12 @@ public: class OpenGLSamplerState : public SamplerState { public: - // Old school. Should also support using a sampler object. - - GLint wrapS; - GLint wrapT; + GLint wrapU; + GLint wrapV; + GLint wrapW; GLint magFilt; GLint minFilt; GLint mipMinFilt; - - void Apply(bool hasMips, bool canWrap) { - if (canWrap) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT); - } else { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilt); - if (hasMips) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mipMinFilt); - } else { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilt); - } - } }; class OpenGLDepthStencilState : public DepthStencilState { @@ -437,6 +420,7 @@ private: }; class OpenGLFramebuffer; +class OpenGLTexture; class OpenGLContext : public DrawContext { public: @@ -484,23 +468,12 @@ public: void GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) override; void BindSamplerStates(int start, int count, SamplerState **states) override { - if (samplerStates_.size() < (size_t)(start + count)) { - samplerStates_.resize(start + count); + if (boundSamplers_.size() < (size_t)(start + count)) { + boundSamplers_.resize(start + count); } - for (int i = 0; i < count; ++i) { + for (int i = 0; i < count; i++) { int index = i + start; - OpenGLSamplerState *s = static_cast(states[index]); - - if (samplerStates_[index]) { - samplerStates_[index]->Release(); - } - samplerStates_[index] = s; - samplerStates_[index]->AddRef(); - - // TODO: Ideally, get these from the texture and apply on the right stage? - if (index == 0) { - s->Apply(false, true); - } + boundSamplers_[index] = static_cast(states[index]); } } @@ -535,7 +508,7 @@ public: curIBufferOffset_ = offset; } - void UpdateDynamicUniformBuffer(const void *ub, size_t size); + void UpdateDynamicUniformBuffer(const void *ub, size_t size) override; // TODO: Add more sophisticated draws. void Draw(int vertexCount, int offset) override; @@ -581,13 +554,16 @@ public: void HandleEvent(Event ev) override {} +private: OpenGLFramebuffer *fbo_ext_create(const FramebufferDesc &desc); void fbo_bind_fb_target(bool read, GLuint name); GLenum fbo_get_fb_target(bool read, GLuint **cached); void fbo_unbind(); + void ApplySamplers(); -private: - std::vector samplerStates_; + std::vector boundSamplers_; + OpenGLTexture *boundTextures_[8]{}; + int maxTextures_ = 0; DeviceCaps caps_; // Bound state @@ -619,12 +595,7 @@ OpenGLContext::OpenGLContext() { } OpenGLContext::~OpenGLContext() { - for (OpenGLSamplerState *s : samplerStates_) { - if (s) { - s->Release(); - } - } - samplerStates_.clear(); + boundSamplers_.clear(); } InputLayout *OpenGLContext::CreateInputLayout(const InputLayoutDesc &desc) { @@ -646,7 +617,9 @@ GLuint TypeToTarget(TextureType type) { case TextureType::ARRAY1D: return GL_TEXTURE_1D_ARRAY; #endif case TextureType::ARRAY2D: return GL_TEXTURE_2D_ARRAY; - default: return GL_NONE; + default: + ELOG("Bad texture type %d", (int)type); + return GL_NONE; } } @@ -659,44 +632,49 @@ public: OpenGLTexture(const TextureDesc &desc); ~OpenGLTexture(); - void AutoGenMipmaps(); - - bool HasMips() { + bool HasMips() const { return mipLevels_ > 1 || generatedMips_; } - bool CanWrap() { + bool CanWrap() const { return canWrap_; } - + TextureType GetType() const { return type_; } void Bind() { glBindTexture(target_, tex_); } + void AutoGenMipmaps(); + private: void SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data); - GLuint tex_; - GLuint target_; + GLuint tex_ = 0; + GLuint target_ = 0; DataFormat format_; + TextureType type_; int mipLevels_; bool generatedMips_; bool canWrap_; }; -OpenGLTexture::OpenGLTexture(const TextureDesc &desc) : tex_(0), target_(TypeToTarget(desc.type)), format_(desc.format), mipLevels_(desc.mipLevels) { +OpenGLTexture::OpenGLTexture(const TextureDesc &desc) { generatedMips_ = false; canWrap_ = true; width_ = desc.width; height_ = desc.height; depth_ = desc.depth; - canWrap_ = !isPowerOf2(width_) || !isPowerOf2(height_); - - glGenTextures(1, &tex_); - + format_ = desc.format; + type_ = desc.type; + target_ = TypeToTarget(desc.type); + canWrap_ = isPowerOf2(width_) && isPowerOf2(height_); if (!desc.initData.size()) return; + glActiveTexture(GL_TEXTURE0 + 0); + glGenTextures(1, &tex_); + glBindTexture(target_, tex_); + int level = 0; for (auto data : desc.initData) { SetImageData(0, 0, 0, width_, height_, depth_, level, 0, data); @@ -704,19 +682,25 @@ OpenGLTexture::OpenGLTexture(const TextureDesc &desc) : tex_(0), target_(TypeToT height_ = (height_ + 1) / 2; level++; } + mipLevels_ = level; #ifdef USING_GLES2 if (gl_extensions.GLES3) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, level - 1); + glTexParameteri(target_, GL_TEXTURE_MAX_LEVEL, level - 1); } #else - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, level - 1); + glTexParameteri(target_, GL_TEXTURE_MAX_LEVEL, level - 1); #endif - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, level > 1 ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(target_, GL_TEXTURE_MIN_FILTER, level > 1 ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR); + glTexParameteri(target_, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - if (desc.initData.size() < desc.mipLevels) + if (desc.initData.size() < desc.mipLevels) { + ILOG("Generating mipmaps"); AutoGenMipmaps(); + } + + // Unbind. + glBindTexture(target_, 0); } OpenGLTexture::~OpenGLTexture() { @@ -727,16 +711,10 @@ OpenGLTexture::~OpenGLTexture() { } } -Texture *OpenGLContext::CreateTexture(const TextureDesc &desc) { - return new OpenGLTexture(desc); -} - void OpenGLTexture::AutoGenMipmaps() { if (!generatedMips_) { - Bind(); + glBindTexture(target_, tex_); glGenerateMipmap(target_); - // TODO: Really, this should follow the sampler state. - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); generatedMips_ = true; } } @@ -775,13 +753,7 @@ void OpenGLTexture::SetImageData(int x, int y, int z, int width, int height, int ELOG("Thin3d GL: Unsupported texture format %d", (int)format_); return; } - /* - GLenum err = glGetError(); - if (err) { - ELOG("Thin3D GL: Error before loading texture: %08x", err); - }*/ - Bind(); switch (target_) { case GL_TEXTURE_2D: glTexImage2D(GL_TEXTURE_2D, level, internalFormat, width_, height_, 0, format, type, data); @@ -797,6 +769,10 @@ void OpenGLTexture::SetImageData(int x, int y, int z, int width, int height, int } } +Texture *OpenGLContext::CreateTexture(const TextureDesc &desc) { + return new OpenGLTexture(desc); +} + OpenGLInputLayout::~OpenGLInputLayout() { if (id_) { glDeleteVertexArrays(1, &id_); @@ -862,8 +838,9 @@ BlendState *OpenGLContext::CreateBlendState(const BlendStateDesc &desc) { SamplerState *OpenGLContext::CreateSamplerState(const SamplerStateDesc &desc) { OpenGLSamplerState *samps = new OpenGLSamplerState(); - samps->wrapS = texWrapToGL[(int)desc.wrapU]; - samps->wrapT = texWrapToGL[(int)desc.wrapV]; + samps->wrapU = texWrapToGL[(int)desc.wrapU]; + samps->wrapV = texWrapToGL[(int)desc.wrapV]; + samps->wrapW = texWrapToGL[(int)desc.wrapW]; samps->magFilt = texFilterToGL[(int)desc.magFilter]; samps->minFilt = texFilterToGL[(int)desc.minFilter]; samps->mipMinFilt = texMipFilterToGL[(int)desc.minFilter][(int)desc.mipFilter]; @@ -990,22 +967,49 @@ Pipeline *OpenGLContext::CreateGraphicsPipeline(const PipelineDesc &desc) { } void OpenGLContext::BindTextures(int start, int count, Texture **textures) { + maxTextures_ = std::max(maxTextures_, start + count); for (int i = start; i < start + count; i++) { OpenGLTexture *glTex = static_cast(textures[i]); glActiveTexture(GL_TEXTURE0 + i); if (!glTex) { + boundTextures_[i] = 0; glBindTexture(GL_TEXTURE_2D, 0); continue; } glTex->Bind(); - - if ((int)samplerStates_.size() > i && samplerStates_[i]) { - samplerStates_[i]->Apply(glTex->HasMips(), glTex->CanWrap()); - } + boundTextures_[i] = glTex; } glActiveTexture(GL_TEXTURE0); } +void OpenGLContext::ApplySamplers() { + for (int i = 0; i < maxTextures_; i++) { + if ((int)boundSamplers_.size() > i && boundSamplers_[i]) { + const OpenGLSamplerState *samp = boundSamplers_[i]; + const OpenGLTexture *tex = boundTextures_[i]; + if (!tex) + continue; + if (tex->CanWrap()) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, samp->wrapU); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, samp->wrapV); +#ifndef USING_GLES2 + if (tex->GetType() == TextureType::LINEAR3D) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, samp->wrapW); +#endif + } else { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, samp->magFilt); + if (tex->HasMips()) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, samp->mipMinFilt); + } else { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, samp->minFilt); + } + } + } +} ShaderModule *OpenGLContext::CreateShaderModule(ShaderStage stage, ShaderLanguage language, const uint8_t *data, size_t dataSize) { OpenGLShaderModule *shader = new OpenGLShaderModule(stage); @@ -1112,6 +1116,7 @@ void OpenGLContext::UpdateDynamicUniformBuffer(const void *ub, size_t size) { void OpenGLContext::Draw(int vertexCount, int offset) { curVBuffers_[0]->Bind(curVBufferOffsets_[0]); curPipeline_->inputLayout->Apply(); + ApplySamplers(); glDrawArrays(curPipeline_->prim, offset, vertexCount); @@ -1121,6 +1126,7 @@ void OpenGLContext::Draw(int vertexCount, int offset) { void OpenGLContext::DrawIndexed(int vertexCount, int offset) { curVBuffers_[0]->Bind(curVBufferOffsets_[0]); curPipeline_->inputLayout->Apply(); + ApplySamplers(); // Note: ibuf binding is stored in the VAO, so call this after binding the fmt. curIBuffer_->Bind(curIBufferOffset_); @@ -1131,6 +1137,7 @@ void OpenGLContext::DrawIndexed(int vertexCount, int offset) { void OpenGLContext::DrawUP(const void *vdata, int vertexCount) { curPipeline_->inputLayout->Apply(vdata); + ApplySamplers(); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); From b75e299b4fd662ad3e5e403fe791c763056428ce Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Sun, 19 Feb 2017 13:11:35 +0100 Subject: [PATCH 5/5] Linux buildfix --- ext/native/gfx_es2/draw_text.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/native/gfx_es2/draw_text.cpp b/ext/native/gfx_es2/draw_text.cpp index 54e67246bd..040047bbe8 100644 --- a/ext/native/gfx_es2/draw_text.cpp +++ b/ext/native/gfx_es2/draw_text.cpp @@ -488,7 +488,7 @@ void TextDrawer::DrawString(DrawBuffer &target, const char *str, float x, float bitmapData[entry->bmWidth * y + x] = 0xfff0 | image.pixel(x, y) >> 28; } } - desc.initData.push_back(bitmapData); + desc.initData.push_back((uint8_t *)bitmapData); entry->texture = draw_->CreateTexture(desc); delete [] bitmapData; cache_[entryHash] = std::unique_ptr(entry);