diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index 403458097..a21f0a703 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -18,6 +18,7 @@ #include #include "Common/ChunkFile.h" +#include "Common/GraphicsContext.h" #include "base/NativeApp.h" #include "base/logging.h" #include "profiler/profiler.h" @@ -391,8 +392,8 @@ static const CommandTableEntry commandTable[] = { DIRECTX9_GPU::CommandInfo DIRECTX9_GPU::cmdInfo_[256]; -DIRECTX9_GPU::DIRECTX9_GPU() -: resized_(false) { +DIRECTX9_GPU::DIRECTX9_GPU(GraphicsContext *gfxCtx) +: resized_(false), gfxCtx_(gfxCtx) { lastVsync_ = g_Config.bVSync ? 1 : 0; dxstate.SetVSyncInterval(g_Config.bVSync); @@ -500,11 +501,12 @@ DIRECTX9_GPU::~DIRECTX9_GPU() { // Needs to be called on GPU thread, not reporting thread. void DIRECTX9_GPU::BuildReportingInfo() { - D3DADAPTER_IDENTIFIER9 identifier = {0}; - pD3D->GetAdapterIdentifier(D3DADAPTER_DEFAULT, 0, &identifier); + Thin3DContext *thin3d = gfxCtx_->CreateThin3DContext(); - reportingPrimaryInfo_ = identifier.Description; - reportingFullInfo_ = reportingPrimaryInfo_ + " - " + System_GetProperty(SYSPROP_GPUDRIVER_VERSION); + reportingPrimaryInfo_ = thin3d->GetInfoString(T3DInfo::VENDORSTRING); + reportingFullInfo_ = reportingPrimaryInfo_ + " - " + System_GetProperty(SYSPROP_GPUDRIVER_VERSION) + " - " + thin3d->GetInfoString(T3DInfo::SHADELANGVERSION); + + thin3d->Release(); } void DIRECTX9_GPU::DeviceLost() { diff --git a/GPU/Directx9/GPU_DX9.h b/GPU/Directx9/GPU_DX9.h index 9fe8e31fa..2e9ae3efa 100644 --- a/GPU/Directx9/GPU_DX9.h +++ b/GPU/Directx9/GPU_DX9.h @@ -35,7 +35,7 @@ class LinkedShaderDX9; class DIRECTX9_GPU : public GPUCommon { public: - DIRECTX9_GPU(); + DIRECTX9_GPU(GraphicsContext *gfxCtx); ~DIRECTX9_GPU(); void CheckGPUFeatures(); void InitClear() override; @@ -187,6 +187,8 @@ private: std::string reportingPrimaryInfo_; std::string reportingFullInfo_; + + GraphicsContext *gfxCtx_; }; } // namespace DX9 diff --git a/GPU/GPU.cpp b/GPU/GPU.cpp index 6b2a6b830..915d953bf 100644 --- a/GPU/GPU.cpp +++ b/GPU/GPU.cpp @@ -50,11 +50,11 @@ bool GPU_Init(GraphicsContext *ctx) { SetGPU(new GLES_GPU(ctx)); break; case GPU_SOFTWARE: - SetGPU(new SoftGPU()); + SetGPU(new SoftGPU(ctx)); break; case GPU_DIRECTX9: #if defined(_WIN32) - SetGPU(new DIRECTX9_GPU()); + SetGPU(new DIRECTX9_GPU(ctx)); #endif break; } diff --git a/GPU/Software/SoftGpu.cpp b/GPU/Software/SoftGpu.cpp index 0a9e9cb1f..d14d7872e 100644 --- a/GPU/Software/SoftGpu.cpp +++ b/GPU/Software/SoftGpu.cpp @@ -15,11 +15,11 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. - #include "GPU/GPUState.h" #include "GPU/ge_constants.h" #include "GPU/Common/TextureDecoder.h" #include "Common/ColorConv.h" +#include "Common/GraphicsContext.h" #include "Core/Config.h" #include "Core/Debugger/Breakpoints.h" #include "Core/Host.h" @@ -28,68 +28,45 @@ #include "Core/HLE/sceGe.h" #include "Core/MIPS/MIPS.h" #include "Core/Reporting.h" -#include "gfx/gl_common.h" -#include "gfx_es2/glsl_program.h" -#include "gfx_es2/gpu_features.h" #include "profiler/profiler.h" +#include "thin3d/thin3d.h" #include "GPU/Software/SoftGpu.h" #include "GPU/Software/TransformUnit.h" #include "GPU/Software/Rasterizer.h" #include "GPU/Common/FramebufferCommon.h" -static GLuint temp_texture = 0; - -static GLSLProgram *program; -static GLuint vao; -static GLuint vbuf; - const int FB_WIDTH = 480; const int FB_HEIGHT = 272; FormatBuffer fb; FormatBuffer depthbuf; u32 clut[4096]; -SoftGPU::SoftGPU() +static Thin3DContext *thin3d = nullptr; +static Thin3DTexture *fbTex = nullptr; +static Thin3DVertexFormat *vformat = nullptr; +static Thin3DDepthStencilState *depth = nullptr; +static Thin3DBuffer *vdata = nullptr; +static Thin3DBuffer *idata = nullptr; +static std::vector fbTexBuffer; + +SoftGPU::SoftGPU(GraphicsContext *gfxCtx) + : gfxCtx_(gfxCtx) { - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 4-byte pixel alignment - glGenTextures(1, &temp_texture); + thin3d = gfxCtx_->CreateThin3DContext(); + fbTex = thin3d->CreateTexture(LINEAR2D, RGBA8888, 480, 272, 1, 1); - // TODO: Use highp for GLES - static const char *fragShaderText = -#ifdef USING_GLES2 - "#version 100\n" -#endif - "varying vec2 texcoord;\n" - "uniform sampler2D sampler0;\n" - "void main() {\n" - " gl_FragColor = texture2D(sampler0, texcoord);\n" - "}\n"; - static const char *vertShaderText = -#ifdef USING_GLES2 - "#version 100\n" -#endif - "attribute vec4 a_position;\n" - "attribute vec2 a_texcoord0;\n " - "varying vec2 texcoord;\n " - "void main() {\n" - " gl_Position = a_position;\n" - " texcoord = a_texcoord0;\n" - "}\n"; + std::vector components; + components.push_back(Thin3DVertexComponent("Position", SEM_POSITION, FLOATx3, 0)); + components.push_back(Thin3DVertexComponent("TexCoord0", SEM_TEXCOORD0, FLOATx2, 12)); + components.push_back(Thin3DVertexComponent("Color0", SEM_COLOR0, UNORM8x4, 20)); - std::string errorString; - program = glsl_create_source(vertShaderText, fragShaderText, &errorString); - if (!program) { - ERROR_LOG_REPORT(G3D, "Failed to compile softgpu program! This shouldn't happen.\n%s", errorString.c_str()); - } else { - glsl_bind(program); - } + Thin3DShader *vshader = thin3d->GetVshaderPreset(VS_TEXTURE_COLOR_2D); + vformat = thin3d->CreateVertexFormat(components, 24, vshader); - if (gl_extensions.ARB_vertex_array_object) { - glGenVertexArrays(1, &vao); - glGenBuffers(1, &vbuf); - } + vdata = thin3d->CreateBuffer(24 * 4, T3DBufferUsage::DYNAMIC | T3DBufferUsage::VERTEXDATA); + idata = thin3d->CreateBuffer(sizeof(int) * 6, T3DBufferUsage::DYNAMIC | T3DBufferUsage::INDEXDATA); + depth = thin3d->CreateDepthStencilState(false, false, T3DComparison::LESS); fb.data = Memory::GetPointer(0x44000000); // TODO: correct default address? depthbuf.data = Memory::GetPointer(0x44000000); // TODO: correct default address? @@ -102,24 +79,16 @@ SoftGPU::SoftGPU() } void SoftGPU::DeviceLost() { - if (vao != 0) { - // These deletes will likely fail, but let's try just in case. - glDeleteVertexArrays(1, &vao); - glDeleteBuffers(1, &vbuf); - - glGenVertexArrays(1, &vao); - glGenBuffers(1, &vbuf); - } + // Handled by thin3d. } -SoftGPU::~SoftGPU() -{ - glsl_destroy(program); - glDeleteTextures(1, &temp_texture); - if (vao != 0) { - glDeleteVertexArrays(1, &vao); - glDeleteBuffers(1, &vbuf); - } +SoftGPU::~SoftGPU() { + vformat->Release(); + vformat = nullptr; + fbTex->Release(); + fbTex = nullptr; + thin3d->Release(); + thin3d = nullptr; } void SoftGPU::SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) { @@ -136,48 +105,51 @@ void SoftGPU::CopyToCurrentFboFromDisplayRam(int srcwidth, int srcheight) float dstwidth = (float)PSP_CoreParameter().pixelWidth; float dstheight = (float)PSP_CoreParameter().pixelHeight; - glDisable(GL_BLEND); - glViewport(0, 0, dstwidth, dstheight); - glDisable(GL_SCISSOR_TEST); + T3DViewport viewport = {0.0f, 0.0f, dstwidth, dstheight, 0.0f, 1.0f}; + thin3d->SetViewports(1, &viewport); - glBindTexture(GL_TEXTURE_2D, temp_texture); + thin3d->SetBlendState(thin3d->GetBlendStatePreset(BS_OFF)); + Thin3DSamplerState *sampler; + if (g_Config.iBufFilter == SCALE_NEAREST) { + sampler = thin3d->GetSamplerStatePreset(T3DSamplerStatePreset::SAMPS_NEAREST); + } else { + sampler = thin3d->GetSamplerStatePreset(T3DSamplerStatePreset::SAMPS_LINEAR); + } + thin3d->SetSamplerStates(0, 1, &sampler); + thin3d->SetDepthStencilState(depth); + thin3d->SetRenderState(T3DRenderState::CULL_MODE, T3DCullMode::NO_CULL); + thin3d->SetScissorEnabled(false); - GLfloat texvert_u; + float u0 = 0.0f; + float u1; if (displayFramebuf_ == 0) { - u32 data[] = {0}; - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); - texvert_u = 1.0f; + u8 data[] = {0, 0, 0, 0}; + fbTex->SetImageData(0, 0, 0, 1, 1, 1, 0, 4, data); + u1 = 1.0f; } else if (displayFormat_ == GE_FORMAT_8888) { u8 *data = Memory::GetPointer(displayFramebuf_); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)displayStride_, (GLsizei)srcheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); - texvert_u = (float)srcwidth / displayStride_; + fbTex->SetImageData(0, 0, 0, displayStride_, srcheight, 1, 0, displayStride_ * 4, data); + u1 = (float)srcwidth / displayStride_; } else { // TODO: This should probably be converted in a shader instead.. - // TODO: Do something less brain damaged to manage this buffer... - u32 *buf = new u32[srcwidth * srcheight]; + fbTexBuffer.resize(srcwidth * srcheight); FormatBuffer displayBuffer; displayBuffer.data = Memory::GetPointer(displayFramebuf_); for (int y = 0; y < srcheight; ++y) { - u32 *buf_line = &buf[y * srcwidth]; + u32 *buf_line = &fbTexBuffer[y * srcwidth]; const u16 *fb_line = &displayBuffer.as16[y * displayStride_]; switch (displayFormat_) { case GE_FORMAT_565: - for (int x = 0; x < srcwidth; ++x) { - buf_line[x] = RGB565ToRGBA8888(fb_line[x]); - } + ConvertRGBA565ToRGBA8888(buf_line, fb_line, srcwidth); break; case GE_FORMAT_5551: - for (int x = 0; x < srcwidth; ++x) { - buf_line[x] = RGBA5551ToRGBA8888(fb_line[x]); - } + ConvertRGBA5551ToRGBA8888(buf_line, fb_line, srcwidth); break; case GE_FORMAT_4444: - for (int x = 0; x < srcwidth; ++x) { - buf_line[x] = RGBA4444ToRGBA8888(fb_line[x]); - } + ConvertRGBA4444ToRGBA8888(buf_line, fb_line, srcwidth); break; default: @@ -185,20 +157,19 @@ void SoftGPU::CopyToCurrentFboFromDisplayRam(int srcwidth, int srcheight) } } - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)srcwidth, (GLsizei)srcheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, buf); - texvert_u = 1.0f; - - delete[] buf; + fbTex->SetImageData(0, 0, 0, srcwidth, srcheight, 1, 0, srcwidth * 4, (const uint8_t *)&fbTexBuffer[0]); + u1 = 1.0f; } - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, g_Config.iBufFilter == SCALE_NEAREST ? GL_NEAREST : GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, g_Config.iBufFilter == SCALE_NEAREST ? GL_NEAREST : GL_LINEAR); - - glsl_bind(program); + fbTex->Finalize(0); float x, y, w, h; CenterDisplayOutputRect(&x, &y, &w, &h, 480.0f, 272.0f, dstwidth, dstheight, ROTATION_LOCKED_HORIZONTAL); + if (GetGPUBackend() == GPUBackend::DIRECT3D9) { + x += 0.5f; + y += 0.5f; + } + x /= 0.5f * dstwidth; y /= 0.5f * dstheight; w /= 0.5f * dstwidth; @@ -210,53 +181,37 @@ void SoftGPU::CopyToCurrentFboFromDisplayRam(int srcwidth, int srcheight) x2 -= 1.0f; y2 -= 1.0f; - const GLfloat verts[4][2] = { - { x, y }, // Left top - { x, y2}, // left bottom - { x2, y2}, // right bottom - { x2, y} // right top + struct Vertex { + float x, y, z; + float u, v; + uint32_t rgba; }; - const GLfloat texverts[4][2] = { - {0, 1}, - {0, 0}, - {texvert_u, 0}, - {texvert_u, 1} + float v0 = 1.0f; + float v1 = 0.0f; + + 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 }; + vdata->SetData((const uint8_t *)verts, sizeof(verts)); - if (vao != 0) { - glBindVertexArray(vao); - glBindBuffer(GL_ARRAY_BUFFER, vbuf); - glBufferData(GL_ARRAY_BUFFER, sizeof(verts) + sizeof(texverts), nullptr, GL_STREAM_DRAW); - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(verts), verts); - glBufferSubData(GL_ARRAY_BUFFER, sizeof(verts), sizeof(texverts), texverts); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + int indexes[] = {0, 1, 2, 0, 2, 3}; + idata->SetData((const uint8_t *)indexes, sizeof(indexes)); - glVertexAttribPointer(program->a_position, 2, GL_FLOAT, GL_FALSE, 0, 0); - glVertexAttribPointer(program->a_texcoord0, 2, GL_FLOAT, GL_FALSE, 0, (void *)sizeof(verts)); - } else { - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + thin3d->SetTexture(0, fbTex); + Thin3DShaderSet *texColor = thin3d->GetShaderSetPreset(SS_TEXTURE_COLOR_2D); - glVertexAttribPointer(program->a_position, 2, GL_FLOAT, GL_FALSE, 0, verts); - glVertexAttribPointer(program->a_texcoord0, 2, GL_FLOAT, GL_FALSE, 0, texverts); - } - - glEnableVertexAttribArray(program->a_position); - glEnableVertexAttribArray(program->a_texcoord0); - glActiveTexture(GL_TEXTURE0); - glUniform1i(program->sampler0, 0); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - glDisableVertexAttribArray(program->a_position); - glDisableVertexAttribArray(program->a_texcoord0); - - glBindTexture(GL_TEXTURE_2D, 0); - - if (vao != 0) { - glBindVertexArray(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - } + 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, + }; + texColor->SetMatrix4x4("WorldViewProj", identity4x4); + thin3d->DrawIndexed(T3DPrimitive::PRIM_TRIANGLES, texColor, vformat, vdata, idata, 6, 0); } void SoftGPU::CopyDisplayToOutput() diff --git a/GPU/Software/SoftGpu.h b/GPU/Software/SoftGpu.h index 749bf4890..423b4f22d 100644 --- a/GPU/Software/SoftGpu.h +++ b/GPU/Software/SoftGpu.h @@ -48,7 +48,7 @@ class ShaderManager; class SoftGPU : public GPUCommon { public: - SoftGPU(); + SoftGPU(GraphicsContext *gfxCtx); ~SoftGPU(); void InitClear() override {} void ExecuteOp(u32 op, u32 diff) override; @@ -100,4 +100,6 @@ private: u32 displayFramebuf_; u32 displayStride_; GEBufferFormat displayFormat_; + + GraphicsContext *gfxCtx_; }; diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index e01fed343..a3fc17294 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -98,10 +98,13 @@ void EmuScreen::bootGame(const std::string &filename) { CoreParameter coreParam; coreParam.cpuCore = g_Config.bJit ? CPU_JIT : CPU_INTERPRETER; - coreParam.gpuCore = g_Config.bSoftwareRendering ? GPU_SOFTWARE : GPU_GLES; + coreParam.gpuCore = GPU_GLES; if (GetGPUBackend() == GPUBackend::DIRECT3D9) { coreParam.gpuCore = GPU_DIRECTX9; } + if (g_Config.bSoftwareRendering) { + coreParam.gpuCore = GPU_SOFTWARE; + } // Preserve the existing graphics context. coreParam.graphicsContext = PSP_CoreParameter().graphicsContext; coreParam.enableSound = g_Config.bEnableSound; diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index ecb0f45ca..9a7462b49 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -331,7 +331,7 @@ void GameSettingsScreen::CreateViews() { CheckBox *softwareGPU = graphicsSettings->Add(new CheckBox(&g_Config.bSoftwareRendering, gr->T("Software Rendering", "Software Rendering (experimental)"))); softwareGPU->OnClick.Handle(this, &GameSettingsScreen::OnSoftwareRendering); - if (PSP_IsInited() || g_Config.iGPUBackend != GPU_BACKEND_OPENGL) + if (PSP_IsInited()) softwareGPU->SetEnabled(false); // Audio @@ -886,11 +886,6 @@ void GameSettingsScreen::CallbackRenderingBackend(bool yes) { // If the user ends up deciding not to restart, set the config back to the current backend // so it doesn't get switched by accident. if (yes) { - if (g_Config.iGPUBackend == (int)GPUBackend::DIRECT3D9) { - // TODO: Remove once software renderer supports D3D9. - g_Config.bSoftwareRendering = false; - } - g_Config.bRestartRequired = true; PostMessage(MainWindow::GetHWND(), WM_CLOSE, 0, 0); } else { diff --git a/Windows/MainWindowMenu.cpp b/Windows/MainWindowMenu.cpp index 47c737821..b2cd04a89 100644 --- a/Windows/MainWindowMenu.cpp +++ b/Windows/MainWindowMenu.cpp @@ -691,8 +691,6 @@ namespace MainWindow { case ID_OPTIONS_DIRECT3D9: g_Config.iGPUBackend = GPU_BACKEND_DIRECT3D9; - // TODO: Remove once software renderer supports D3D9. - g_Config.bSoftwareRendering = false; g_Config.bRestartRequired = true; PostMessage(MainWindow::GetHWND(), WM_CLOSE, 0, 0); break; diff --git a/Windows/main.cpp b/Windows/main.cpp index 7faef1bf2..2ba054996 100644 --- a/Windows/main.cpp +++ b/Windows/main.cpp @@ -472,13 +472,10 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin if (restOfOption == L"directx9") { g_Config.iGPUBackend = GPU_BACKEND_DIRECT3D9; g_Config.bSoftwareRendering = false; - } - else if (restOfOption == L"gles") { + } else if (restOfOption == L"gles") { g_Config.iGPUBackend = GPU_BACKEND_OPENGL; g_Config.bSoftwareRendering = false; - } - - else if (restOfOption == L"software") { + } else if (restOfOption == L"software") { g_Config.iGPUBackend = GPU_BACKEND_OPENGL; g_Config.bSoftwareRendering = true; } diff --git a/ext/native/gfx_es2/draw_buffer.cpp b/ext/native/gfx_es2/draw_buffer.cpp index 527fee59d..298997743 100644 --- a/ext/native/gfx_es2/draw_buffer.cpp +++ b/ext/native/gfx_es2/draw_buffer.cpp @@ -80,7 +80,7 @@ void DrawBuffer::Flush(bool set_blend_state) { if (count_ == 0) return; - shaderSet_->SetMatrix4x4("WorldViewProj", drawMatrix_); + shaderSet_->SetMatrix4x4("WorldViewProj", drawMatrix_.getReadPtr()); if (vbuf_) { vbuf_->SubData((const uint8_t *)verts_, 0, sizeof(Vertex) * count_); diff --git a/ext/native/thin3d/thin3d.cpp b/ext/native/thin3d/thin3d.cpp index e72a8d67a..78dd46a9d 100644 --- a/ext/native/thin3d/thin3d.cpp +++ b/ext/native/thin3d/thin3d.cpp @@ -94,6 +94,12 @@ void Thin3DContext::CreatePresets() { bsPresets_[BS_STANDARD_ALPHA] = CreateBlendState(standard_alpha); bsPresets_[BS_PREMUL_ALPHA] = CreateBlendState(premul_alpha); + T3DSamplerStateDesc nearest = { CLAMP, CLAMP, NEAREST, NEAREST, NEAREST }; + T3DSamplerStateDesc linear = { CLAMP, CLAMP, LINEAR, LINEAR, NEAREST }; + + sampsPresets_[SAMPS_NEAREST] = CreateSamplerState(nearest); + sampsPresets_[SAMPS_LINEAR] = CreateSamplerState(linear); + vsPresets_[VS_TEXTURE_COLOR_2D] = CreateVertexShader(glsl_vsTexCol, hlslVsTexCol); vsPresets_[VS_COLOR_2D] = CreateVertexShader(glsl_vsCol, hlslVsCol); diff --git a/ext/native/thin3d/thin3d.h b/ext/native/thin3d/thin3d.h index 4a73aa75b..1593778d5 100644 --- a/ext/native/thin3d/thin3d.h +++ b/ext/native/thin3d/thin3d.h @@ -66,6 +66,16 @@ enum T3DBlendFactor : int { FIXED_COLOR, }; +enum T3DTextureWrap : int { + REPEAT, + CLAMP, +}; + +enum T3DTextureFilter : int { + NEAREST, + LINEAR, +}; + enum T3DBufferUsage : int { VERTEXDATA = 1, INDEXDATA = 2, @@ -126,6 +136,12 @@ enum T3DBlendStatePreset : int { BS_MAX_PRESET, }; +enum T3DSamplerStatePreset : int { + SAMPS_NEAREST, + SAMPS_LINEAR, + SAMPS_MAX_PRESET, +}; + enum T3DClear : int { COLOR = 1, DEPTH = 2, @@ -207,6 +223,10 @@ class Thin3DBlendState : public Thin3DObject { public: }; +class Thin3DSamplerState : public Thin3DObject { +public: +}; + class Thin3DDepthStencilState : public Thin3DObject { public: }; @@ -262,7 +282,7 @@ class Thin3DShaderSet : public Thin3DObject { public: // TODO: Make some faster way of doing these. Support uniform buffers (and fake them on GL 2.0?) virtual void SetVector(const char *name, float *value, int n) = 0; - virtual void SetMatrix4x4(const char *name, const Matrix4x4 &value) = 0; + virtual void SetMatrix4x4(const char *name, const float value[16]) = 0; }; struct T3DBlendStateDesc { @@ -278,6 +298,14 @@ struct T3DBlendStateDesc { // int colorMask; }; +struct T3DSamplerStateDesc { + T3DTextureWrap wrapS; + T3DTextureWrap wrapT; + T3DTextureFilter magFilt; + T3DTextureFilter minFilt; + T3DTextureFilter mipFilt; +}; + class Thin3DContext : public Thin3DObject { public: virtual ~Thin3DContext(); @@ -286,6 +314,7 @@ public: virtual Thin3DDepthStencilState *CreateDepthStencilState(bool depthTestEnabled, bool depthWriteEnabled, T3DComparison depthCompare) = 0; virtual Thin3DBlendState *CreateBlendState(const T3DBlendStateDesc &desc) = 0; + virtual Thin3DSamplerState *CreateSamplerState(const T3DSamplerStateDesc &desc) = 0; virtual Thin3DBuffer *CreateBuffer(size_t size, uint32_t usageFlags) = 0; virtual Thin3DShaderSet *CreateShaderSet(Thin3DShader *vshader, Thin3DShader *fshader) = 0; virtual Thin3DVertexFormat *CreateVertexFormat(const std::vector &components, int stride, Thin3DShader *vshader) = 0; @@ -299,6 +328,7 @@ public: // Note that these DO NOT AddRef so you must not ->Release presets unless you manually AddRef them. Thin3DBlendState *GetBlendStatePreset(T3DBlendStatePreset preset) { return bsPresets_[preset]; } + Thin3DSamplerState *GetSamplerStatePreset(T3DSamplerStatePreset preset) { return sampsPresets_[preset]; } Thin3DShader *GetVshaderPreset(T3DVertexShaderPreset preset) { return fsPresets_[preset]; } Thin3DShader *GetFshaderPreset(T3DFragmentShaderPreset preset) { return vsPresets_[preset]; } Thin3DShaderSet *GetShaderSetPreset(T3DShaderSetPreset preset) { return ssPresets_[preset]; } @@ -309,6 +339,7 @@ public: // Bound state objects. Too cumbersome to add them all as parameters to Draw. virtual void SetBlendState(Thin3DBlendState *state) = 0; + virtual void SetSamplerStates(int start, int count, Thin3DSamplerState **state) = 0; virtual void SetDepthStencilState(Thin3DDepthStencilState *state) = 0; virtual void SetTextures(int start, int count, Thin3DTexture **textures) = 0; @@ -345,6 +376,7 @@ protected: Thin3DShader *fsPresets_[FS_MAX_PRESET]; Thin3DBlendState *bsPresets_[BS_MAX_PRESET]; Thin3DShaderSet *ssPresets_[SS_MAX_PRESET]; + Thin3DSamplerState *sampsPresets_[SAMPS_MAX_PRESET]; int targetWidth_; int targetHeight_; diff --git a/ext/native/thin3d/thin3d_d3d9.cpp b/ext/native/thin3d/thin3d_d3d9.cpp index 78bd12199..d5e1e3edf 100644 --- a/ext/native/thin3d/thin3d_d3d9.cpp +++ b/ext/native/thin3d/thin3d_d3d9.cpp @@ -56,12 +56,28 @@ static const D3DBLEND blendFactorToD3D9[] = { D3DBLEND_BLENDFACTOR, }; +static const D3DTEXTUREADDRESS texWrapToD3D9[] = { + D3DTADDRESS_WRAP, + D3DTADDRESS_CLAMP, +}; + +static const D3DTEXTUREFILTERTYPE texFilterToD3D9[] = { + D3DTEXF_POINT, + D3DTEXF_LINEAR, +}; + static const D3DPRIMITIVETYPE primToD3D9[] = { D3DPT_POINTLIST, D3DPT_LINELIST, D3DPT_TRIANGLELIST, }; +static const int primCountDivisor[] = { + 1, + 2, + 3, +}; + class Thin3DDX9DepthStencilState : public Thin3DDepthStencilState { public: BOOL depthTestEnabled; @@ -94,6 +110,20 @@ public: } }; +class Thin3DDX9SamplerState : public Thin3DSamplerState { +public: + D3DTEXTUREADDRESS wrapS, wrapT; + D3DTEXTUREFILTERTYPE magFilt, minFilt, mipFilt; + + void Apply(LPDIRECT3DDEVICE9 device, int index) { + device->SetSamplerState(index, D3DSAMP_ADDRESSU, wrapS); + device->SetSamplerState(index, D3DSAMP_ADDRESSV, wrapT); + device->SetSamplerState(index, D3DSAMP_MAGFILTER, magFilt); + device->SetSamplerState(index, D3DSAMP_MINFILTER, minFilt); + device->SetSamplerState(index, D3DSAMP_MIPFILTER, mipFilt); + } +}; + class Thin3DDX9Buffer : public Thin3DBuffer { public: Thin3DDX9Buffer(LPDIRECT3DDEVICE9 device, size_t size, uint32_t flags) : vbuffer_(nullptr), ibuffer_(nullptr), maxSize_(size) { @@ -212,7 +242,7 @@ public: } } void SetVector(LPDIRECT3DDEVICE9 device, const char *name, float *value, int n); - void SetMatrix4x4(LPDIRECT3DDEVICE9 device, const char *name, const Matrix4x4 &value); + void SetMatrix4x4(LPDIRECT3DDEVICE9 device, const char *name, const float value[16]); private: bool isPixelShader_; @@ -228,7 +258,7 @@ public: Thin3DDX9Shader *pshader; void Apply(LPDIRECT3DDEVICE9 device); void SetVector(const char *name, float *value, int n) { vshader->SetVector(device_, name, value, n); pshader->SetVector(device_, name, value, n); } - void SetMatrix4x4(const char *name, const Matrix4x4 &value) { vshader->SetMatrix4x4(device_, name, value); } // pshaders don't usually have matrices + void SetMatrix4x4(const char *name, const float value[16]) { vshader->SetMatrix4x4(device_, name, value); } // pshaders don't usually have matrices private: LPDIRECT3DDEVICE9 device_; }; @@ -397,6 +427,7 @@ public: Thin3DDepthStencilState *CreateDepthStencilState(bool depthTestEnabled, bool depthWriteEnabled, T3DComparison depthCompare); Thin3DBlendState *CreateBlendState(const T3DBlendStateDesc &desc) override; + Thin3DSamplerState *CreateSamplerState(const T3DSamplerStateDesc &desc) override; Thin3DBuffer *CreateBuffer(size_t size, uint32_t usageFlags) override; Thin3DShaderSet *CreateShaderSet(Thin3DShader *vshader, Thin3DShader *fshader) override; Thin3DVertexFormat *CreateVertexFormat(const std::vector &components, int stride, Thin3DShader *vshader) override; @@ -411,6 +442,12 @@ public: Thin3DDX9BlendState *bs = static_cast(state); bs->Apply(device_); } + void SetSamplerStates(int start, int count, Thin3DSamplerState **states) { + for (int i = 0; i < count; ++i) { + Thin3DDX9SamplerState *s = static_cast(states[start + i]); + s->Apply(device_, start + i); + } + } void SetDepthStencilState(Thin3DDepthStencilState *state) { Thin3DDX9DepthStencilState *bs = static_cast(state); bs->Apply(device_); @@ -522,6 +559,16 @@ Thin3DBlendState *Thin3DDX9Context::CreateBlendState(const T3DBlendStateDesc &de return bs; } +Thin3DSamplerState *Thin3DDX9Context::CreateSamplerState(const T3DSamplerStateDesc &desc) { + Thin3DDX9SamplerState *samps = new Thin3DDX9SamplerState(); + samps->wrapS = texWrapToD3D9[desc.wrapS]; + samps->wrapT = texWrapToD3D9[desc.wrapT]; + samps->magFilt = texFilterToD3D9[desc.magFilt]; + samps->minFilt = texFilterToD3D9[desc.minFilt]; + samps->mipFilt = texFilterToD3D9[desc.mipFilt]; + return samps; +} + Thin3DTexture *Thin3DDX9Context::CreateTexture() { Thin3DDX9Texture *tex = new Thin3DDX9Texture(device_, deviceEx_); return tex; @@ -625,12 +672,6 @@ void Thin3DDX9Context::Draw(T3DPrimitive prim, Thin3DShaderSet *shaderSet, Thin3 Thin3DDX9VertexFormat *fmt = static_cast(format); Thin3DDX9ShaderSet *ss = static_cast(shaderSet); - device_->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); - device_->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); - device_->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); - device_->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); - device_->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); - vbuf->BindAsVertexBuf(device_, fmt->GetStride(), offset); ss->Apply(device_); fmt->Apply(device_); @@ -647,19 +688,13 @@ void Thin3DDX9Context::DrawIndexed(T3DPrimitive prim, Thin3DShaderSet *shaderSet fmt->Apply(device_); vbuf->BindAsVertexBuf(device_, fmt->GetStride(), offset); ibuf->BindAsIndexBuf(device_); - device_->DrawIndexedPrimitive(primToD3D9[prim], 0, 0, vertexCount, 0, vertexCount / 3); + device_->DrawIndexedPrimitive(primToD3D9[prim], 0, 0, vertexCount, 0, vertexCount / primCountDivisor[prim]); } void Thin3DDX9Context::DrawUP(T3DPrimitive prim, Thin3DShaderSet *shaderSet, Thin3DVertexFormat *format, const void *vdata, int vertexCount) { Thin3DDX9VertexFormat *fmt = static_cast(format); Thin3DDX9ShaderSet *ss = static_cast(shaderSet); - device_->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); - device_->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); - device_->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); - device_->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); - device_->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); - ss->Apply(device_); fmt->Apply(device_); device_->DrawPrimitiveUP(primToD3D9[prim], vertexCount / 3, vdata, fmt->GetStride()); @@ -757,10 +792,10 @@ void Thin3DDX9Shader::SetVector(LPDIRECT3DDEVICE9 device, const char *name, floa } } -void Thin3DDX9Shader::SetMatrix4x4(LPDIRECT3DDEVICE9 device, const char *name, const Matrix4x4 &value) { +void Thin3DDX9Shader::SetMatrix4x4(LPDIRECT3DDEVICE9 device, const char *name, const float value[16]) { D3DXHANDLE handle = constantTable_->GetConstantByName(NULL, name); if (handle) { - constantTable_->SetFloatArray(device, handle, value.getReadPtr(), 16); + constantTable_->SetFloatArray(device, handle, value, 16); } } diff --git a/ext/native/thin3d/thin3d_gl.cpp b/ext/native/thin3d/thin3d_gl.cpp index 0bcf1ccfe..70453fc32 100644 --- a/ext/native/thin3d/thin3d_gl.cpp +++ b/ext/native/thin3d/thin3d_gl.cpp @@ -43,6 +43,23 @@ static const unsigned short blendFactorToGL[] = { GL_CONSTANT_COLOR, }; +static const unsigned short texWrapToGL[] = { + GL_REPEAT, + GL_CLAMP_TO_EDGE, +}; + +static const unsigned short texFilterToGL[] = { + GL_NEAREST, + GL_LINEAR, +}; + +static const unsigned short texMipFilterToGL[2][2] = { + // Min nearest: + { GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR }, + // Min linear: + { GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_LINEAR }, +}; + #ifndef USING_GLES2 static const unsigned short logicOpToGL[] = { GL_CLEAR, @@ -108,6 +125,32 @@ public: } }; +class Thin3DGLSamplerState : public Thin3DSamplerState { +public: + GLint wrapS; + GLint wrapT; + 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 Thin3DGLDepthStencilState : public Thin3DDepthStencilState { public: bool depthTestEnabled; @@ -278,7 +321,7 @@ public: int GetUniformLoc(const char *name); void SetVector(const char *name, float *value, int n) override; - void SetMatrix4x4(const char *name, const Matrix4x4 &value) override; + void SetMatrix4x4(const char *name, const float value[16]) override; void GLRestore() override { vshader->Compile(vshader->GetSource().c_str()); @@ -301,6 +344,7 @@ public: Thin3DDepthStencilState *CreateDepthStencilState(bool depthTestEnabled, bool depthWriteEnabled, T3DComparison depthCompare) override; Thin3DBlendState *CreateBlendState(const T3DBlendStateDesc &desc) override; + Thin3DSamplerState *CreateSamplerState(const T3DSamplerStateDesc &desc) override; Thin3DBuffer *CreateBuffer(size_t size, uint32_t usageFlags) override; Thin3DShaderSet *CreateShaderSet(Thin3DShader *vshader, Thin3DShader *fshader) override; Thin3DVertexFormat *CreateVertexFormat(const std::vector &components, int stride, Thin3DShader *vshader) override; @@ -313,6 +357,28 @@ public: s->Apply(); } + void SetSamplerStates(int start, int count, Thin3DSamplerState **states) override { + if (samplerStates_.size() < (size_t)(start + count)) { + samplerStates_.resize(start + count); + } + for (int i = 0; i < count; ++i) { + int index = i + start; + Thin3DGLSamplerState *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); + } + } + + } + // Bound state objects void SetDepthStencilState(Thin3DDepthStencilState *state) override { Thin3DGLDepthStencilState *s = static_cast(state); @@ -385,6 +451,8 @@ public: default: return "?"; } } + + std::vector samplerStates_; }; Thin3DGLContext::Thin3DGLContext() { @@ -392,6 +460,12 @@ Thin3DGLContext::Thin3DGLContext() { } Thin3DGLContext::~Thin3DGLContext() { + for (Thin3DGLSamplerState *s : samplerStates_) { + if (s) { + s->Release(); + } + } + samplerStates_.clear(); } Thin3DVertexFormat *Thin3DGLContext::CreateVertexFormat(const std::vector &components, int stride, Thin3DShader *vshader) { @@ -422,6 +496,7 @@ class Thin3DGLTexture : public Thin3DTexture, GfxResourceHolder { public: Thin3DGLTexture() : tex_(0), target_(0) { generatedMips_ = false; + canWrap_ = true; width_ = 0; height_ = 0; depth_ = 0; @@ -430,6 +505,7 @@ public: } Thin3DGLTexture(T3DTextureType type, T3DImageFormat format, int width, int height, int depth, int mipLevels) : tex_(0), target_(TypeToTarget(type)), format_(format), mipLevels_(mipLevels) { generatedMips_ = false; + canWrap_ = true; width_ = width; height_ = height; depth_ = depth; @@ -443,6 +519,7 @@ public: bool Create(T3DTextureType type, T3DImageFormat format, int width, int height, int depth, int mipLevels) override { generatedMips_ = false; + canWrap_ = true; format_ = format; target_ = TypeToTarget(type); mipLevels_ = mipLevels; @@ -462,6 +539,13 @@ public: 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() override; + bool HasMips() { + return mipLevels_ > 1 || generatedMips_; + } + bool CanWrap() { + return canWrap_; + } + void Bind() { glBindTexture(target_, tex_); } @@ -491,6 +575,7 @@ private: T3DImageFormat format_; int mipLevels_; bool generatedMips_; + bool canWrap_; }; Thin3DTexture *Thin3DGLContext::CreateTexture() { @@ -505,6 +590,7 @@ void Thin3DGLTexture::AutoGenMipmaps() { if (!generatedMips_) { Bind(); glGenerateMipmap(target_); + // TODO: Really, this should follow the sampler state. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); generatedMips_ = true; } @@ -528,6 +614,11 @@ void Thin3DGLTexture::SetImageData(int x, int y, int z, int width, int height, i default: return; } + if (level == 0) { + width_ = width; + height_ = height; + depth_ = depth; + } Bind(); switch (target_) { @@ -545,17 +636,7 @@ bool isPowerOf2(int n) { } void Thin3DGLTexture::Finalize(int zim_flags) { - GLenum wrap = GL_REPEAT; - if ((zim_flags & ZIM_CLAMP) || !isPowerOf2(width_) || !isPowerOf2(height_)) - wrap = GL_CLAMP_TO_EDGE; - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - if ((zim_flags & (ZIM_HAS_MIPS | ZIM_GEN_MIPS))) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); - } else { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } + canWrap_ = (zim_flags & ZIM_CLAMP) || !isPowerOf2(width_) || !isPowerOf2(height_); } @@ -610,6 +691,16 @@ Thin3DBlendState *Thin3DGLContext::CreateBlendState(const T3DBlendStateDesc &des return bs; } +Thin3DSamplerState *Thin3DGLContext::CreateSamplerState(const T3DSamplerStateDesc &desc) { + Thin3DGLSamplerState *samps = new Thin3DGLSamplerState(); + samps->wrapS = texWrapToGL[desc.wrapS]; + samps->wrapT = texWrapToGL[desc.wrapT]; + samps->magFilt = texFilterToGL[desc.magFilt]; + samps->minFilt = texFilterToGL[desc.minFilt]; + samps->mipMinFilt = texMipFilterToGL[desc.minFilt][desc.mipFilt]; + return samps; +} + Thin3DBuffer *Thin3DGLContext::CreateBuffer(size_t size, uint32_t usageFlags) { return new Thin3DGLBuffer(size, usageFlags); } @@ -637,6 +728,10 @@ void Thin3DGLContext::SetTextures(int start, int count, Thin3DTexture **textures Thin3DGLTexture *glTex = static_cast(textures[i]); glActiveTexture(GL_TEXTURE0 + i); glTex->Bind(); + + if (samplerStates_.size() > i && samplerStates_[i]) { + samplerStates_[i]->Apply(glTex->HasMips(), glTex->CanWrap()); + } } glActiveTexture(GL_TEXTURE0); } @@ -737,11 +832,11 @@ void Thin3DGLShaderSet::SetVector(const char *name, float *value, int n) { } } -void Thin3DGLShaderSet::SetMatrix4x4(const char *name, const Matrix4x4 &value) { +void Thin3DGLShaderSet::SetMatrix4x4(const char *name, const float value[16]) { glUseProgram(program_); int loc = GetUniformLoc(name); if (loc != -1) { - glUniformMatrix4fv(loc, 1, false, value.getReadPtr()); + glUniformMatrix4fv(loc, 1, false, value); } } @@ -791,8 +886,8 @@ void Thin3DGLContext::DrawIndexed(T3DPrimitive prim, Thin3DShaderSet *shaderSet, ss->Apply(); // Note: ibuf binding is stored in the VAO, so call this after binding the fmt. ibuf->Bind(); - - glDrawElements(primToGL[prim], offset, GL_INT, 0); + + glDrawElements(primToGL[prim], vertexCount, GL_UNSIGNED_INT, (const void *)(size_t)offset); ss->Unapply(); fmt->Unapply(); @@ -805,6 +900,8 @@ void Thin3DGLContext::DrawUP(T3DPrimitive prim, Thin3DShaderSet *shaderSet, Thin fmt->Apply(vdata); ss->Apply(); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glDrawArrays(primToGL[prim], 0, vertexCount); ss->Unapply(); diff --git a/ext/native/ui/ui_context.cpp b/ext/native/ui/ui_context.cpp index c81228808..020c23623 100644 --- a/ext/native/ui/ui_context.cpp +++ b/ext/native/ui/ui_context.cpp @@ -23,6 +23,7 @@ UIContext::~UIContext() { void UIContext::Init(Thin3DContext *thin3d, Thin3DShaderSet *uishader, Thin3DShaderSet *uishadernotex, Thin3DTexture *uitexture, DrawBuffer *uidrawbuffer, DrawBuffer *uidrawbufferTop) { thin3d_ = thin3d; blend_ = thin3d_->GetBlendStatePreset(T3DBlendStatePreset::BS_STANDARD_ALPHA); + sampler_ = thin3d_->GetSamplerStatePreset(T3DSamplerStatePreset::SAMPS_LINEAR); depth_ = thin3d_->CreateDepthStencilState(false, false, T3DComparison::LESS); uishader_ = uishader; @@ -39,6 +40,7 @@ void UIContext::Init(Thin3DContext *thin3d, Thin3DShaderSet *uishader, Thin3DSha void UIContext::Begin() { thin3d_->SetBlendState(blend_); + thin3d_->SetSamplerStates(0, 1, &sampler_); thin3d_->SetDepthStencilState(depth_); thin3d_->SetRenderState(T3DRenderState::CULL_MODE, T3DCullMode::NO_CULL); thin3d_->SetTexture(0, uitexture_); @@ -48,6 +50,7 @@ void UIContext::Begin() { void UIContext::BeginNoTex() { thin3d_->SetBlendState(blend_); + thin3d_->SetSamplerStates(0, 1, &sampler_); thin3d_->SetRenderState(T3DRenderState::CULL_MODE, T3DCullMode::NO_CULL); UIBegin(uishadernotex_); diff --git a/ext/native/ui/ui_context.h b/ext/native/ui/ui_context.h index 628a96cba..3fba861d6 100644 --- a/ext/native/ui/ui_context.h +++ b/ext/native/ui/ui_context.h @@ -14,6 +14,7 @@ class Thin3DShaderSet; class Thin3DDepthStencilState; class Thin3DTexture; class Thin3DBlendState; +class Thin3DSamplerState; class Texture; class DrawBuffer; class TextDrawer; @@ -82,6 +83,7 @@ private: Thin3DContext *thin3D_; Thin3DDepthStencilState *depth_; Thin3DBlendState *blend_; + Thin3DSamplerState *sampler_; Thin3DShaderSet *uishader_; Thin3DShaderSet *uishadernotex_; Thin3DTexture *uitexture_;