mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-23 13:30:02 +00:00
Change the API for updating buffers from the CPU to be cleaner
This commit is contained in:
parent
534a65c610
commit
d78d3bb25f
@ -236,10 +236,10 @@ void SoftGPU::CopyToCurrentFboFromDisplayRam(int srcwidth, int srcheight) {
|
||||
{ x2, y2, 0, u1, v1, 0xFFFFFFFF }, // BR
|
||||
{ x2, y, 0, u1, v0, 0xFFFFFFFF }, // TR
|
||||
};
|
||||
vdata->SubData((const uint8_t *)verts, 0, sizeof(verts));
|
||||
draw_->UpdateBuffer(vdata, (const uint8_t *)verts, 0, sizeof(verts));
|
||||
|
||||
int indexes[] = { 0, 1, 2, 0, 2, 3 };
|
||||
idata->SubData((const uint8_t *)indexes, 0, sizeof(indexes));
|
||||
draw_->UpdateBuffer(idata, (const uint8_t *)indexes, 0, sizeof(indexes));
|
||||
|
||||
draw_->BindTexture(0, fbTex);
|
||||
|
||||
|
@ -93,7 +93,7 @@ void DrawBuffer::Flush(bool set_blend_state) {
|
||||
pipeline_->SetMatrix4x4("WorldViewProj", drawMatrix_.getReadPtr());
|
||||
draw_->BindPipeline(pipeline_);
|
||||
if (vbuf_) {
|
||||
vbuf_->SubData((const uint8_t *)verts_, 0, sizeof(Vertex) * count_);
|
||||
draw_->UpdateBuffer(vbuf_, (const uint8_t *)verts_, 0, sizeof(Vertex) * count_);
|
||||
draw_->BindVertexBuffers(0, 1, &vbuf_, nullptr);
|
||||
int offset = 0;
|
||||
draw_->Draw(count_, offset);
|
||||
|
@ -388,7 +388,6 @@ public:
|
||||
|
||||
class Buffer : public RefCountedObject {
|
||||
public:
|
||||
virtual void SubData(const uint8_t *data, size_t offset, size_t size) = 0;
|
||||
};
|
||||
|
||||
class Texture : public RefCountedObject {
|
||||
|
@ -701,12 +701,10 @@ public:
|
||||
buf->Release();
|
||||
if (srView)
|
||||
srView->Release();
|
||||
}
|
||||
virtual void SubData(const uint8_t *data, size_t offset, size_t size) override {
|
||||
|
||||
}
|
||||
ID3D11Buffer *buf;
|
||||
ID3D11ShaderResourceView *srView;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
Buffer *D3D11DrawContext::CreateBuffer(size_t size, uint32_t usageFlags) {
|
||||
@ -720,8 +718,11 @@ Buffer *D3D11DrawContext::CreateBuffer(size_t size, uint32_t usageFlags) {
|
||||
desc.BindFlags |= D3D11_BIND_INDEX_BUFFER;
|
||||
if (usageFlags & UNIFORM)
|
||||
desc.BindFlags |= D3D11_BIND_CONSTANT_BUFFER;
|
||||
|
||||
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
||||
desc.Usage = D3D11_USAGE_DYNAMIC;
|
||||
|
||||
b->size = size;
|
||||
HRESULT hr = device_->CreateBuffer(&desc, nullptr, &b->buf);
|
||||
if (FAILED(hr)) {
|
||||
delete b;
|
||||
@ -732,7 +733,20 @@ Buffer *D3D11DrawContext::CreateBuffer(size_t size, uint32_t usageFlags) {
|
||||
}
|
||||
|
||||
void D3D11DrawContext::UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, size_t size) {
|
||||
Crash();
|
||||
D3D11Buffer *buf = (D3D11Buffer *)buffer;
|
||||
if (offset == 0 && size == buf->size) {
|
||||
// Can just discard the old contents. This is only allowed for DYNAMIC buffers.
|
||||
D3D11_MAPPED_SUBRESOURCE map;
|
||||
context_->Map(buf->buf, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
|
||||
memcpy(map.pData, data, size);
|
||||
context_->Unmap(buf->buf, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
D3D11_BOX box{};
|
||||
box.left = offset;
|
||||
box.right = offset + size;
|
||||
context_->UpdateSubresource(buf->buf, 0, &box, data, 0, 0);
|
||||
}
|
||||
|
||||
void D3D11DrawContext::BindVertexBuffers(int start, int count, Buffer **buffers, int *offsets) {
|
||||
|
@ -142,6 +142,8 @@ static int FormatToD3DDeclType(DataFormat type) {
|
||||
}
|
||||
}
|
||||
|
||||
class D3D9Buffer;
|
||||
|
||||
class D3D9DepthStencilState : public DepthStencilState {
|
||||
public:
|
||||
BOOL depthTestEnabled;
|
||||
@ -219,58 +221,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
// Simulate a simple buffer type like the other backends have, use the usage flags to create the right internal type.
|
||||
class D3D9Buffer : public Buffer {
|
||||
public:
|
||||
D3D9Buffer(LPDIRECT3DDEVICE9 device, size_t size, uint32_t flags) : vbuffer_(nullptr), ibuffer_(nullptr), maxSize_(size) {
|
||||
if (flags & BufferUsageFlag::INDEXDATA) {
|
||||
DWORD usage = D3DUSAGE_DYNAMIC;
|
||||
device->CreateIndexBuffer((UINT)size, usage, D3DFMT_INDEX32, D3DPOOL_DEFAULT, &ibuffer_, NULL);
|
||||
}
|
||||
else {
|
||||
DWORD usage = D3DUSAGE_DYNAMIC;
|
||||
device->CreateVertexBuffer((UINT)size, usage, 0, D3DPOOL_DEFAULT, &vbuffer_, NULL);
|
||||
}
|
||||
}
|
||||
virtual ~D3D9Buffer() override {
|
||||
if (ibuffer_) {
|
||||
ibuffer_->Release();
|
||||
}
|
||||
if (vbuffer_) {
|
||||
vbuffer_->Release();
|
||||
}
|
||||
}
|
||||
|
||||
void SubData(const uint8_t *data, size_t offset, size_t size) override {
|
||||
if (!size)
|
||||
return;
|
||||
if (offset + size > maxSize_) {
|
||||
ELOG("Can't SubData with bigger size than buffer was created with");
|
||||
return;
|
||||
}
|
||||
if (vbuffer_) {
|
||||
void *ptr;
|
||||
HRESULT res = vbuffer_->Lock((UINT)offset, (UINT)size, &ptr, D3DLOCK_DISCARD);
|
||||
if (!FAILED(res)) {
|
||||
memcpy(ptr, data, size);
|
||||
vbuffer_->Unlock();
|
||||
}
|
||||
} else if (ibuffer_) {
|
||||
void *ptr;
|
||||
HRESULT res = ibuffer_->Lock((UINT)offset, (UINT)size, &ptr, D3DLOCK_DISCARD);
|
||||
if (!FAILED(res)) {
|
||||
memcpy(ptr, data, size);
|
||||
ibuffer_->Unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
LPDIRECT3DVERTEXBUFFER9 vbuffer_;
|
||||
LPDIRECT3DINDEXBUFFER9 ibuffer_;
|
||||
size_t maxSize_;
|
||||
};
|
||||
|
||||
class D3D9InputLayout : public InputLayout {
|
||||
public:
|
||||
D3D9InputLayout(LPDIRECT3DDEVICE9 device, const InputLayoutDesc &desc);
|
||||
@ -831,12 +781,59 @@ D3D9InputLayout::D3D9InputLayout(LPDIRECT3DDEVICE9 device, const InputLayoutDesc
|
||||
delete[] elements;
|
||||
}
|
||||
|
||||
// Simulate a simple buffer type like the other backends have, use the usage flags to create the right internal type.
|
||||
class D3D9Buffer : public Buffer {
|
||||
public:
|
||||
D3D9Buffer(LPDIRECT3DDEVICE9 device, size_t size, uint32_t flags) : vbuffer_(nullptr), ibuffer_(nullptr), maxSize_(size) {
|
||||
if (flags & BufferUsageFlag::INDEXDATA) {
|
||||
DWORD usage = D3DUSAGE_DYNAMIC;
|
||||
device->CreateIndexBuffer((UINT)size, usage, D3DFMT_INDEX32, D3DPOOL_DEFAULT, &ibuffer_, NULL);
|
||||
} else {
|
||||
DWORD usage = D3DUSAGE_DYNAMIC;
|
||||
device->CreateVertexBuffer((UINT)size, usage, 0, D3DPOOL_DEFAULT, &vbuffer_, NULL);
|
||||
}
|
||||
}
|
||||
virtual ~D3D9Buffer() override {
|
||||
if (ibuffer_) {
|
||||
ibuffer_->Release();
|
||||
}
|
||||
if (vbuffer_) {
|
||||
vbuffer_->Release();
|
||||
}
|
||||
}
|
||||
|
||||
LPDIRECT3DVERTEXBUFFER9 vbuffer_;
|
||||
LPDIRECT3DINDEXBUFFER9 ibuffer_;
|
||||
size_t maxSize_;
|
||||
};
|
||||
|
||||
Buffer *D3D9Context::CreateBuffer(size_t size, uint32_t usageFlags) {
|
||||
return new D3D9Buffer(device_, size, usageFlags);
|
||||
}
|
||||
|
||||
void D3D9Context::UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, size_t size) {
|
||||
Crash();
|
||||
D3D9Buffer *buf = (D3D9Buffer *)buffer;
|
||||
if (!size)
|
||||
return;
|
||||
if (offset + size > buf->maxSize_) {
|
||||
ELOG("Can't SubData with bigger size than buffer was created with");
|
||||
return;
|
||||
}
|
||||
if (buf->vbuffer_) {
|
||||
void *ptr;
|
||||
HRESULT res = buf->vbuffer_->Lock((UINT)offset, (UINT)size, &ptr, D3DLOCK_DISCARD);
|
||||
if (!FAILED(res)) {
|
||||
memcpy(ptr, data, size);
|
||||
buf->vbuffer_->Unlock();
|
||||
}
|
||||
} else if (buf->ibuffer_) {
|
||||
void *ptr;
|
||||
HRESULT res = buf->ibuffer_->Lock((UINT)offset, (UINT)size, &ptr, D3DLOCK_DISCARD);
|
||||
if (!FAILED(res)) {
|
||||
memcpy(ptr, data, size);
|
||||
buf->ibuffer_->Unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void D3D9Pipeline::Apply(LPDIRECT3DDEVICE9 device) {
|
||||
|
@ -153,6 +153,8 @@ static const unsigned short primToGL[] = {
|
||||
#endif
|
||||
};
|
||||
|
||||
class OpenGLBuffer;
|
||||
|
||||
static const char *glsl_fragment_prelude =
|
||||
"#ifdef GL_ES\n"
|
||||
"precision mediump float;\n"
|
||||
@ -270,56 +272,6 @@ public:
|
||||
GLenum frontFace;
|
||||
};
|
||||
|
||||
class OpenGLBuffer : public Buffer, GfxResourceHolder {
|
||||
public:
|
||||
OpenGLBuffer(size_t size, uint32_t flags) {
|
||||
glGenBuffers(1, &buffer_);
|
||||
target_ = (flags & BufferUsageFlag::INDEXDATA) ? GL_ELEMENT_ARRAY_BUFFER : GL_ARRAY_BUFFER;
|
||||
usage_ = 0;
|
||||
if (flags & BufferUsageFlag::DYNAMIC)
|
||||
usage_ = GL_STREAM_DRAW;
|
||||
else
|
||||
usage_ = GL_STATIC_DRAW;
|
||||
totalSize_ = size;
|
||||
glBindBuffer(target_, buffer_);
|
||||
glBufferData(target_, size, NULL, usage_);
|
||||
register_gl_resource_holder(this);
|
||||
}
|
||||
~OpenGLBuffer() override {
|
||||
unregister_gl_resource_holder(this);
|
||||
glDeleteBuffers(1, &buffer_);
|
||||
}
|
||||
|
||||
void SubData(const uint8_t *data, size_t offset, size_t size) override {
|
||||
Bind(0);
|
||||
if (size + offset > totalSize_) {
|
||||
Crash();
|
||||
}
|
||||
glBufferSubData(target_, offset, size, data);
|
||||
}
|
||||
void Bind(int offset) {
|
||||
// TODO: Can't support offset using ES 2.0
|
||||
glBindBuffer(target_, buffer_);
|
||||
}
|
||||
|
||||
void GLLost() override {
|
||||
buffer_ = 0;
|
||||
}
|
||||
|
||||
void GLRestore() override {
|
||||
ILOG("Recreating vertex buffer after gl_restore");
|
||||
totalSize_ = 0; // Will cause a new glBufferData call. Should genBuffers again though?
|
||||
glGenBuffers(1, &buffer_);
|
||||
}
|
||||
|
||||
private:
|
||||
GLuint buffer_;
|
||||
GLuint target_;
|
||||
GLuint usage_;
|
||||
|
||||
size_t totalSize_;
|
||||
};
|
||||
|
||||
GLuint ShaderStageToOpenGL(ShaderStage stage) {
|
||||
switch (stage) {
|
||||
case ShaderStage::VERTEX: return GL_VERTEX_SHADER;
|
||||
@ -935,12 +887,60 @@ RasterState *OpenGLContext::CreateRasterState(const RasterStateDesc &desc) {
|
||||
return rs;
|
||||
}
|
||||
|
||||
class OpenGLBuffer : public Buffer, GfxResourceHolder {
|
||||
public:
|
||||
OpenGLBuffer(size_t size, uint32_t flags) {
|
||||
glGenBuffers(1, &buffer_);
|
||||
target_ = (flags & BufferUsageFlag::INDEXDATA) ? GL_ELEMENT_ARRAY_BUFFER : GL_ARRAY_BUFFER;
|
||||
usage_ = 0;
|
||||
if (flags & BufferUsageFlag::DYNAMIC)
|
||||
usage_ = GL_STREAM_DRAW;
|
||||
else
|
||||
usage_ = GL_STATIC_DRAW;
|
||||
totalSize_ = size;
|
||||
glBindBuffer(target_, buffer_);
|
||||
glBufferData(target_, size, NULL, usage_);
|
||||
register_gl_resource_holder(this);
|
||||
}
|
||||
~OpenGLBuffer() override {
|
||||
unregister_gl_resource_holder(this);
|
||||
glDeleteBuffers(1, &buffer_);
|
||||
}
|
||||
|
||||
void Bind(int offset) {
|
||||
// TODO: Can't support offset using ES 2.0
|
||||
glBindBuffer(target_, buffer_);
|
||||
}
|
||||
|
||||
void GLLost() override {
|
||||
buffer_ = 0;
|
||||
}
|
||||
|
||||
void GLRestore() override {
|
||||
ILOG("Recreating vertex buffer after gl_restore");
|
||||
totalSize_ = 0; // Will cause a new glBufferData call. Should genBuffers again though?
|
||||
glGenBuffers(1, &buffer_);
|
||||
}
|
||||
|
||||
GLuint buffer_;
|
||||
GLuint target_;
|
||||
GLuint usage_;
|
||||
|
||||
size_t totalSize_;
|
||||
};
|
||||
|
||||
Buffer *OpenGLContext::CreateBuffer(size_t size, uint32_t usageFlags) {
|
||||
return new OpenGLBuffer(size, usageFlags);
|
||||
}
|
||||
|
||||
void OpenGLContext::UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, size_t size) {
|
||||
Crash();
|
||||
OpenGLBuffer *buf = (OpenGLBuffer *)buffer;
|
||||
|
||||
buf->Bind(0);
|
||||
if (size + offset > buf->totalSize_) {
|
||||
Crash();
|
||||
}
|
||||
glBufferSubData(buf->target_, offset, size, data);
|
||||
}
|
||||
|
||||
Pipeline *OpenGLContext::CreateGraphicsPipeline(const PipelineDesc &desc) {
|
||||
|
@ -176,29 +176,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
// Very simplistic buffer that will simply copy its contents into our "pushbuffer" when it's time to draw,
|
||||
// to avoid synchronization issues.
|
||||
class VKBuffer : public Buffer {
|
||||
public:
|
||||
VKBuffer(size_t size, uint32_t flags) : dataSize_(size) {
|
||||
data_ = new uint8_t[size];
|
||||
}
|
||||
~VKBuffer() override {
|
||||
delete[] data_;
|
||||
}
|
||||
|
||||
void SubData(const uint8_t *data, size_t offset, size_t size) override {
|
||||
memcpy(data_, data_ + offset, size);
|
||||
}
|
||||
|
||||
size_t GetSize() const { return dataSize_; }
|
||||
const uint8_t *GetData() const { return data_; }
|
||||
|
||||
private:
|
||||
uint8_t *data_;
|
||||
size_t dataSize_;
|
||||
};
|
||||
|
||||
VkShaderStageFlagBits StageToVulkan(ShaderStage stage) {
|
||||
switch (stage) {
|
||||
case ShaderStage::VERTEX: return VK_SHADER_STAGE_VERTEX_BIT;
|
||||
@ -320,6 +297,7 @@ private:
|
||||
};
|
||||
|
||||
class VKTexture;
|
||||
class VKBuffer;
|
||||
class VKSamplerState;
|
||||
|
||||
struct DescriptorSetKey {
|
||||
@ -1050,12 +1028,31 @@ BlendState *VKContext::CreateBlendState(const BlendStateDesc &desc) {
|
||||
return bs;
|
||||
}
|
||||
|
||||
// Very simplistic buffer that will simply copy its contents into our "pushbuffer" when it's time to draw,
|
||||
// to avoid synchronization issues.
|
||||
class VKBuffer : public Buffer {
|
||||
public:
|
||||
VKBuffer(size_t size, uint32_t flags) : dataSize_(size) {
|
||||
data_ = new uint8_t[size];
|
||||
}
|
||||
~VKBuffer() override {
|
||||
delete[] data_;
|
||||
}
|
||||
|
||||
size_t GetSize() const { return dataSize_; }
|
||||
const uint8_t *GetData() const { return data_; }
|
||||
|
||||
uint8_t *data_;
|
||||
size_t dataSize_;
|
||||
};
|
||||
|
||||
Buffer *VKContext::CreateBuffer(size_t size, uint32_t usageFlags) {
|
||||
return new VKBuffer(size, usageFlags);
|
||||
}
|
||||
|
||||
void VKContext::UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, size_t size) {
|
||||
Crash();
|
||||
VKBuffer *buf = (VKBuffer *)buffer;
|
||||
memcpy(buf->data_ + offset, data, size);
|
||||
}
|
||||
|
||||
void VKContext::BindTextures(int start, int count, Texture **textures) {
|
||||
|
Loading…
Reference in New Issue
Block a user