Merge pull request #8591 from unknownbrackets/thin3d

Use thin3d for softgpu drawing (+thin3d improvements)
This commit is contained in:
Henrik Rydgård 2016-03-20 18:06:53 +01:00
commit 54a37f9bb8
16 changed files with 322 additions and 193 deletions

View File

@ -18,6 +18,7 @@
#include <set>
#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() {

View File

@ -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

View File

@ -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;
}

View File

@ -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<u32> 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<Thin3DVertexComponent> 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()

View File

@ -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_;
};

View File

@ -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;

View File

@ -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 {

View File

@ -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;

View File

@ -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;
}

View File

@ -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_);

View File

@ -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);

View File

@ -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<Thin3DVertexComponent> &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_;

View File

@ -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<Thin3DVertexComponent> &components, int stride, Thin3DShader *vshader) override;
@ -411,6 +442,12 @@ public:
Thin3DDX9BlendState *bs = static_cast<Thin3DDX9BlendState *>(state);
bs->Apply(device_);
}
void SetSamplerStates(int start, int count, Thin3DSamplerState **states) {
for (int i = 0; i < count; ++i) {
Thin3DDX9SamplerState *s = static_cast<Thin3DDX9SamplerState *>(states[start + i]);
s->Apply(device_, start + i);
}
}
void SetDepthStencilState(Thin3DDepthStencilState *state) {
Thin3DDX9DepthStencilState *bs = static_cast<Thin3DDX9DepthStencilState *>(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<Thin3DDX9VertexFormat *>(format);
Thin3DDX9ShaderSet *ss = static_cast<Thin3DDX9ShaderSet*>(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<Thin3DDX9VertexFormat *>(format);
Thin3DDX9ShaderSet *ss = static_cast<Thin3DDX9ShaderSet*>(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);
}
}

View File

@ -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<Thin3DVertexComponent> &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<Thin3DGLSamplerState *>(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<Thin3DGLDepthStencilState *>(state);
@ -385,6 +451,8 @@ public:
default: return "?";
}
}
std::vector<Thin3DGLSamplerState *> 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<Thin3DVertexComponent> &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<Thin3DGLTexture *>(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();

View File

@ -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_);

View File

@ -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_;