mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
DrawContext: Initial implementation of dynamic UBO support
This commit is contained in:
parent
29739c8c91
commit
fe1b593c15
6 changed files with 164 additions and 36 deletions
|
@ -184,10 +184,9 @@ static const std::vector<ShaderSource> vsCol = {
|
|||
}
|
||||
};
|
||||
|
||||
static const UniformBufferDesc vsColBuf { { { 0, UniformType::MATRIX4X4, 0 } } };
|
||||
struct VsColUB {
|
||||
float WorldViewProj[16];
|
||||
};
|
||||
const UniformBufferDesc vsColBufDesc { sizeof(VsColUB), {
|
||||
{ "WorldViewProj", 0, -1, UniformType::MATRIX4X4, 0 }
|
||||
} };
|
||||
|
||||
static const std::vector<ShaderSource> vsTexCol = {
|
||||
{ ShaderLanguage::GLSL_ES_200,
|
||||
|
@ -248,10 +247,9 @@ static const std::vector<ShaderSource> vsTexCol = {
|
|||
}
|
||||
};
|
||||
|
||||
static const UniformBufferDesc vsTexColDesc{ { { 0, UniformType::MATRIX4X4, 0 } } };
|
||||
struct VsTexColUB {
|
||||
float WorldViewProj[16];
|
||||
};
|
||||
const UniformBufferDesc vsTexColBufDesc{ sizeof(VsTexColUB),{
|
||||
{ "WorldViewProj", 0, -1, UniformType::MATRIX4X4, 0 }
|
||||
} };
|
||||
|
||||
static ShaderModule *CreateShader(DrawContext *draw, ShaderStage stage, const std::vector<ShaderSource> &sources) {
|
||||
uint32_t supported = draw->GetSupportedShaderLanguages();
|
||||
|
|
|
@ -430,20 +430,22 @@ struct InputLayoutDesc {
|
|||
class InputLayout : public RefCountedObject { };
|
||||
|
||||
enum class UniformType : int8_t {
|
||||
FLOAT, FLOAT2, FLOAT3, FLOAT4,
|
||||
FLOAT4,
|
||||
MATRIX4X4,
|
||||
};
|
||||
|
||||
// For emulation of uniform buffers on D3D9/GL
|
||||
struct UniformDesc {
|
||||
int16_t offset;
|
||||
const char *name; // For GL
|
||||
int16_t vertexReg; // For D3D
|
||||
int16_t fragmentReg; // For D3D
|
||||
UniformType type;
|
||||
int8_t reg; // For D3D
|
||||
|
||||
int16_t offset;
|
||||
// TODO: Support array elements etc.
|
||||
};
|
||||
|
||||
struct UniformBufferDesc {
|
||||
size_t uniformBufferSize;
|
||||
std::vector<UniformDesc> uniforms;
|
||||
};
|
||||
|
||||
|
@ -520,6 +522,7 @@ struct PipelineDesc {
|
|||
DepthStencilState *depthStencil;
|
||||
BlendState *blend;
|
||||
RasterState *raster;
|
||||
UniformBufferDesc *uniformDesc;
|
||||
};
|
||||
|
||||
struct DeviceCaps {
|
||||
|
@ -602,6 +605,10 @@ public:
|
|||
virtual void BindVertexBuffers(int start, int count, Buffer **buffers, int *offsets) = 0;
|
||||
virtual void BindIndexBuffer(Buffer *indexBuffer, int offset) = 0;
|
||||
|
||||
// Only supports a single dynamic uniform buffer, for maximum compatibility with the old APIs and ease of emulation.
|
||||
// More modern methods will be added later.
|
||||
virtual void UpdateDynamicUniformBuffer(const void *ub, size_t size) = 0;
|
||||
|
||||
void BindTexture(int stage, Texture *texture) {
|
||||
BindTextures(stage, 1, &texture);
|
||||
} // from sampler 0 and upwards
|
||||
|
@ -645,6 +652,8 @@ size_t DataFormatSizeInBytes(DataFormat fmt);
|
|||
|
||||
DrawContext *T3DCreateGLContext();
|
||||
|
||||
extern const UniformBufferDesc UBPresetDesc;
|
||||
|
||||
#ifdef _WIN32
|
||||
DrawContext *T3DCreateDX9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapterId, IDirect3DDevice9 *device, IDirect3DDevice9Ex *deviceEx);
|
||||
DrawContext *T3DCreateD3D11Context(ID3D11Device *device, ID3D11DeviceContext *context, HWND hWnd);
|
||||
|
@ -652,4 +661,15 @@ DrawContext *T3DCreateD3D11Context(ID3D11Device *device, ID3D11DeviceContext *co
|
|||
|
||||
DrawContext *T3DCreateVulkanContext(VulkanContext *context);
|
||||
|
||||
// UBs for the preset shaders
|
||||
|
||||
struct VsTexColUB {
|
||||
float WorldViewProj[16];
|
||||
};
|
||||
extern const UniformBufferDesc vsTexColBufDesc;
|
||||
struct VsColUB {
|
||||
float WorldViewProj[16];
|
||||
};
|
||||
extern const UniformBufferDesc vsColBufDesc;
|
||||
|
||||
} // namespace Draw
|
||||
|
|
|
@ -60,9 +60,11 @@ public:
|
|||
|
||||
void BindTextures(int start, int count, Texture **textures) override;
|
||||
void BindSamplerStates(int start, int count, SamplerState **states) override;
|
||||
void BindPipeline(Pipeline *pipeline) override;
|
||||
void BindVertexBuffers(int start, int count, Buffer **buffers, int *offsets) override;
|
||||
void BindIndexBuffer(Buffer *indexBuffer, int offset) override;
|
||||
void BindPipeline(Pipeline *pipeline) override;
|
||||
|
||||
void UpdateDynamicUniformBuffer(const void *ub, size_t size) override;
|
||||
|
||||
// Raster state
|
||||
void SetScissorRect(int left, int top, int width, int height) override;
|
||||
|
@ -503,11 +505,20 @@ InputLayout *D3D11DrawContext::CreateInputLayout(const InputLayoutDesc &desc) {
|
|||
class D3D11Pipeline : public Pipeline {
|
||||
public:
|
||||
~D3D11Pipeline() {
|
||||
input->Release();
|
||||
blend->Release();
|
||||
depth->Release();
|
||||
raster->Release();
|
||||
il->Release();
|
||||
if (input)
|
||||
input->Release();
|
||||
if (blend)
|
||||
blend->Release();
|
||||
if (depth)
|
||||
depth->Release();
|
||||
if (raster)
|
||||
raster->Release();
|
||||
if (il)
|
||||
il->Release();
|
||||
if (dynamicUniforms)
|
||||
dynamicUniforms->Release();
|
||||
if (dynamicUniformsView)
|
||||
dynamicUniformsView->Release();
|
||||
}
|
||||
// TODO: Refactor away these.
|
||||
void SetVector(const char *name, float *value, int n) { }
|
||||
|
@ -516,15 +527,19 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
D3D11InputLayout *input;
|
||||
D3D11InputLayout *input = nullptr;
|
||||
ID3D11InputLayout *il = nullptr;
|
||||
D3D11BlendState *blend;
|
||||
D3D11DepthStencilState *depth;
|
||||
D3D11RasterState *raster;
|
||||
ID3D11VertexShader *vs;
|
||||
ID3D11PixelShader *ps;
|
||||
ID3D11GeometryShader *gs;
|
||||
D3D11_PRIMITIVE_TOPOLOGY topology;
|
||||
D3D11BlendState *blend = nullptr;
|
||||
D3D11DepthStencilState *depth = nullptr;
|
||||
D3D11RasterState *raster = nullptr;
|
||||
ID3D11VertexShader *vs = nullptr;
|
||||
ID3D11PixelShader *ps = nullptr;
|
||||
ID3D11GeometryShader *gs = nullptr;
|
||||
D3D11_PRIMITIVE_TOPOLOGY topology = D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED;
|
||||
|
||||
size_t dynamicUniformsSize = 0;
|
||||
ID3D11Buffer *dynamicUniforms = nullptr;
|
||||
ID3D11ShaderResourceView *dynamicUniformsView = nullptr;
|
||||
};
|
||||
|
||||
class D3D11Texture : public Texture {
|
||||
|
@ -710,6 +725,22 @@ Pipeline *D3D11DrawContext::CreateGraphicsPipeline(const PipelineDesc &desc) {
|
|||
dPipeline->input->AddRef();
|
||||
dPipeline->raster->AddRef();
|
||||
dPipeline->topology = primToD3D11[(int)desc.prim];
|
||||
if (desc.uniformDesc) {
|
||||
dPipeline->dynamicUniformsSize = desc.uniformDesc->uniformBufferSize;
|
||||
D3D11_BUFFER_DESC bufdesc{};
|
||||
bufdesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
||||
bufdesc.ByteWidth = dPipeline->dynamicUniformsSize;
|
||||
bufdesc.StructureByteStride = dPipeline->dynamicUniformsSize;
|
||||
bufdesc.Usage = D3D11_USAGE_DYNAMIC;
|
||||
bufdesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
|
||||
HRESULT hr = device_->CreateBuffer(&bufdesc, nullptr, &dPipeline->dynamicUniforms);
|
||||
D3D11_SHADER_RESOURCE_VIEW_DESC bufview{};
|
||||
bufview.Buffer.ElementOffset = 0;
|
||||
bufview.Buffer.ElementWidth = dPipeline->dynamicUniformsSize;
|
||||
bufview.Buffer.FirstElement = 0;
|
||||
bufview.Buffer.NumElements = 1;
|
||||
hr = device_->CreateShaderResourceView(dPipeline->dynamicUniforms, &bufview, &dPipeline->dynamicUniformsView);
|
||||
}
|
||||
|
||||
std::vector<D3D11ShaderModule *> shaders;
|
||||
D3D11ShaderModule *vshader = nullptr;
|
||||
|
@ -746,6 +777,16 @@ Pipeline *D3D11DrawContext::CreateGraphicsPipeline(const PipelineDesc &desc) {
|
|||
return dPipeline;
|
||||
}
|
||||
|
||||
void D3D11DrawContext::UpdateDynamicUniformBuffer(const void *ub, size_t size) {
|
||||
if (curPipeline_->dynamicUniformsSize != size) {
|
||||
Crash();
|
||||
}
|
||||
D3D11_MAPPED_SUBRESOURCE map{};
|
||||
context_->Map(curPipeline_->dynamicUniforms, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
|
||||
memcpy(map.pData, ub, size);
|
||||
context_->Unmap(curPipeline_->dynamicUniforms, 0);
|
||||
}
|
||||
|
||||
void D3D11DrawContext::BindPipeline(Pipeline *pipeline) {
|
||||
D3D11Pipeline *dPipeline = (D3D11Pipeline *)pipeline;
|
||||
if (curPipeline_ == dPipeline)
|
||||
|
|
|
@ -291,6 +291,7 @@ public:
|
|||
D3D9DepthStencilState *depthStencil = nullptr;
|
||||
D3D9BlendState *blend = nullptr;
|
||||
D3D9RasterState *raster = nullptr;
|
||||
UniformBufferDesc dynamicUniforms;
|
||||
|
||||
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); }
|
||||
|
@ -520,6 +521,8 @@ public:
|
|||
curPipeline_ = (D3D9Pipeline *)pipeline;
|
||||
}
|
||||
|
||||
void UpdateDynamicUniformBuffer(const void *ub, size_t size) override;
|
||||
|
||||
// Raster state
|
||||
void SetScissorRect(int left, int top, int width, int height) override;
|
||||
void SetViewports(int count, Viewport *viewports) override;
|
||||
|
@ -647,6 +650,8 @@ Pipeline *D3D9Context::CreateGraphicsPipeline(const PipelineDesc &desc) {
|
|||
pipeline->blend->AddRef();
|
||||
pipeline->raster->AddRef();
|
||||
pipeline->inputLayout->AddRef();
|
||||
if (desc.uniformDesc)
|
||||
pipeline->dynamicUniforms = *desc.uniformDesc;
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
|
@ -811,6 +816,29 @@ Buffer *D3D9Context::CreateBuffer(size_t size, uint32_t usageFlags) {
|
|||
return new D3D9Buffer(device_, size, usageFlags);
|
||||
}
|
||||
|
||||
void D3D9Context::UpdateDynamicUniformBuffer(const void *ub, size_t size) {
|
||||
if (size != curPipeline_->dynamicUniforms.uniformBufferSize)
|
||||
Crash();
|
||||
for (auto &uniform : curPipeline_->dynamicUniforms.uniforms) {
|
||||
int count = 0;
|
||||
switch (uniform.type) {
|
||||
case UniformType::FLOAT4:
|
||||
count = 1;
|
||||
break;
|
||||
case UniformType::MATRIX4X4:
|
||||
count = 4;
|
||||
break;
|
||||
}
|
||||
const float *srcPtr = (const float *)((uint8_t *)ub + uniform.offset);
|
||||
if (uniform.vertexReg != -1) {
|
||||
device_->SetVertexShaderConstantF(uniform.vertexReg, srcPtr, count);
|
||||
}
|
||||
if (uniform.fragmentReg != -1) {
|
||||
device_->SetPixelShaderConstantF(uniform.fragmentReg, srcPtr, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void D3D9Context::UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, size_t size, UpdateBufferFlags flags) {
|
||||
D3D9Buffer *buf = (D3D9Buffer *)buffer;
|
||||
if (!size)
|
||||
|
|
|
@ -381,7 +381,6 @@ struct UniformInfo {
|
|||
int loc_;
|
||||
};
|
||||
|
||||
// TODO: Add Uniform Buffer support.
|
||||
class OpenGLPipeline : public Pipeline, GfxResourceHolder {
|
||||
public:
|
||||
OpenGLPipeline() {
|
||||
|
@ -434,9 +433,12 @@ public:
|
|||
OpenGLBlendState *blend = nullptr;
|
||||
OpenGLRasterState *raster = nullptr;
|
||||
|
||||
// TODO: Optimize by getting the locations first and putting in a custom struct
|
||||
UniformBufferDesc dynamicUniforms;
|
||||
|
||||
private:
|
||||
GLuint program_;
|
||||
std::map<std::string, UniformInfo> uniforms_;
|
||||
std::map<std::string, UniformInfo> uniformCache_;
|
||||
};
|
||||
|
||||
class OpenGLFramebuffer;
|
||||
|
@ -538,6 +540,8 @@ public:
|
|||
curIBufferOffset_ = offset;
|
||||
}
|
||||
|
||||
void UpdateDynamicUniformBuffer(const void *ub, size_t size);
|
||||
|
||||
// TODO: Add more sophisticated draws.
|
||||
void Draw(int vertexCount, int offset) override;
|
||||
void DrawIndexed(int vertexCount, int offset) override;
|
||||
|
@ -965,6 +969,8 @@ Pipeline *OpenGLContext::CreateGraphicsPipeline(const PipelineDesc &desc) {
|
|||
pipeline->blend->AddRef();
|
||||
pipeline->raster->AddRef();
|
||||
pipeline->inputLayout->AddRef();
|
||||
if (desc.uniformDesc)
|
||||
pipeline->dynamicUniforms = *desc.uniformDesc;
|
||||
return pipeline;
|
||||
} else {
|
||||
delete pipeline;
|
||||
|
@ -1046,15 +1052,15 @@ bool OpenGLPipeline::LinkShaders() {
|
|||
}
|
||||
|
||||
int OpenGLPipeline::GetUniformLoc(const char *name) {
|
||||
auto iter = uniforms_.find(name);
|
||||
auto iter = uniformCache_.find(name);
|
||||
int loc = -1;
|
||||
if (iter != uniforms_.end()) {
|
||||
if (iter != uniformCache_.end()) {
|
||||
loc = iter->second.loc_;
|
||||
} else {
|
||||
loc = glGetUniformLocation(program_, name);
|
||||
UniformInfo info;
|
||||
info.loc_ = loc;
|
||||
uniforms_[name] = info;
|
||||
uniformCache_[name] = info;
|
||||
}
|
||||
return loc;
|
||||
}
|
||||
|
@ -1095,6 +1101,27 @@ void OpenGLContext::BindPipeline(Pipeline *pipeline) {
|
|||
curPipeline_->raster->Apply();
|
||||
}
|
||||
|
||||
void OpenGLContext::UpdateDynamicUniformBuffer(const void *ub, size_t size) {
|
||||
if (curPipeline_->dynamicUniforms.uniformBufferSize != size) {
|
||||
Crash();
|
||||
}
|
||||
|
||||
for (auto &uniform : curPipeline_->dynamicUniforms.uniforms) {
|
||||
GLuint loc = curPipeline_->GetUniformLoc(uniform.name);
|
||||
if (loc == -1)
|
||||
Crash();
|
||||
const float *data = (const float *)((uint8_t *)ub + uniform.offset);
|
||||
switch (uniform.type) {
|
||||
case UniformType::FLOAT4:
|
||||
glUniform1fv(loc, 4, data);
|
||||
break;
|
||||
case UniformType::MATRIX4X4:
|
||||
glUniformMatrix4fv(loc, 1, false, data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLContext::Draw(int vertexCount, int offset) {
|
||||
curVBuffers_[0]->Bind(curVBufferOffsets_[0]);
|
||||
curPipeline_->inputLayout->Apply();
|
||||
|
|
|
@ -262,15 +262,18 @@ public:
|
|||
|
||||
class VKPipeline : public Pipeline {
|
||||
public:
|
||||
VKPipeline() {
|
||||
// HACK! Hardcoded
|
||||
uboSize_ = 16 * sizeof(float); // WorldViewProj
|
||||
VKPipeline(size_t size) {
|
||||
uboSize_ = size;
|
||||
ubo_ = new uint8_t[uboSize_];
|
||||
}
|
||||
~VKPipeline() {
|
||||
delete[] ubo_;
|
||||
}
|
||||
|
||||
void SetDynamicUniformData(const void *data, size_t size) {
|
||||
memcpy(ubo_, data, size);
|
||||
}
|
||||
|
||||
// Returns the binding offset, and the VkBuffer to bind.
|
||||
size_t PushUBO(VulkanPushBuffer *buf, VulkanContext *vulkan, VkBuffer *vkbuf) {
|
||||
return buf->PushAligned(ubo_, uboSize_, vulkan->GetPhysicalDeviceProperties().limits.minUniformBufferOffsetAlignment, vkbuf);
|
||||
|
@ -289,7 +292,8 @@ public:
|
|||
}
|
||||
|
||||
VkPipeline vkpipeline;
|
||||
int stride[4];
|
||||
int stride[4]{};
|
||||
int dynamicUniformSize = 0;
|
||||
|
||||
private:
|
||||
uint8_t *ubo_;
|
||||
|
@ -376,6 +380,8 @@ public:
|
|||
curIBufferOffset_ = offset;
|
||||
}
|
||||
|
||||
void UpdateDynamicUniformBuffer(const void *ub, size_t size);
|
||||
|
||||
// TODO: Add more sophisticated draws.
|
||||
void Draw(int vertexCount, int offset) override;
|
||||
void DrawIndexed(int vertexCount, int offset) override;
|
||||
|
@ -827,7 +833,7 @@ VkDescriptorSet VKContext::GetOrCreateDescriptorSet(VkBuffer buf) {
|
|||
}
|
||||
|
||||
Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc) {
|
||||
VKPipeline *pipeline = new VKPipeline();
|
||||
VKPipeline *pipeline = new VKPipeline(desc.uniformDesc ? desc.uniformDesc->uniformBufferSize : 16 * sizeof(float));
|
||||
VKInputLayout *input = (VKInputLayout *)desc.inputLayout;
|
||||
VKBlendState *blend = (VKBlendState *)desc.blend;
|
||||
VKDepthStencilState *depth = (VKDepthStencilState *)desc.depthStencil;
|
||||
|
@ -900,6 +906,10 @@ Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc) {
|
|||
delete pipeline;
|
||||
return nullptr;
|
||||
}
|
||||
if (desc.uniformDesc) {
|
||||
pipeline->dynamicUniformSize = desc.uniformDesc->uniformBufferSize;
|
||||
}
|
||||
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
|
@ -1112,6 +1122,10 @@ inline VkPrimitiveTopology PrimToVK(Primitive prim) {
|
|||
}
|
||||
}
|
||||
|
||||
void VKContext::UpdateDynamicUniformBuffer(const void *ub, size_t size) {
|
||||
curPipeline_->SetDynamicUniformData(ub, size);
|
||||
}
|
||||
|
||||
void VKContext::Draw(int vertexCount, int offset) {
|
||||
ApplyDynamicState();
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue