Skip to content
Permalink
Browse files

[d3d9] Implement ProcessVertices (swvp) with geometry shader + buffer

writes

Fixes missing/broken portraits in The Sims 2, and garbage graphics in
software mode.
  • Loading branch information...
Joshua-Ashton committed Aug 8, 2019
1 parent 8772210 commit 48c1df625de26f21c6b32fa6a1ef7f81f8e031dc
@@ -59,9 +59,9 @@ namespace dxvk {
VkMemoryPropertyFlags memoryFlags = 0;

if (m_desc.Type == D3DRTYPE_VERTEXBUFFER) {
info.usage |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
info.stages |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
info.access |= VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
info.usage |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
info.stages |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
info.access |= VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
}
else if (m_desc.Type == D3DRTYPE_INDEXBUFFER) {
info.usage |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
@@ -141,6 +141,8 @@ namespace dxvk {
D3D9Range& LockRange() { return m_lockRange; }
D3D9Range& DirtyRange() { return m_dirtyRange; }

bool SetReadLocked(bool state) { return std::exchange(m_readLocked, state); }

private:

Rc<DxvkBuffer> CreateBuffer() const;
@@ -161,6 +163,7 @@ namespace dxvk {
D3D9DeviceEx* m_parent;
const D3D9_BUFFER_DESC m_desc;
DWORD m_mapFlags;
bool m_readLocked = false;

Rc<DxvkBuffer> m_buffer;
Rc<DxvkBuffer> m_stagingBuffer;
@@ -2211,26 +2211,75 @@ namespace dxvk {
IDirect3DVertexBuffer9* pDestBuffer,
IDirect3DVertexDeclaration9* pVertexDecl,
DWORD Flags) {
Logger::warn("D3D9DeviceEx::ProcessVertices: Stub");
D3D9VertexBuffer* dst = static_cast<D3D9VertexBuffer*>(pDestBuffer);
if (unlikely(pDestBuffer == nullptr || pVertexDecl == nullptr))
return D3DERR_INVALIDCALL;

// Let's avoid some vertex explosions here...
// This is not an actual implementation.
// Just makes some games slightly more playable.
D3D9CommonBuffer* dst = static_cast<D3D9VertexBuffer*>(pDestBuffer)->GetCommonBuffer();
D3D9VertexDecl* decl = static_cast<D3D9VertexDecl*> (pVertexDecl);

if (unlikely(dst == nullptr))
return D3DERR_INVALIDCALL;
PrepareDraw(false);

uint32_t size = dst->GetCommonBuffer()->Desc()->Size;
if (decl == nullptr) {
DWORD FVF = dst->Desc()->FVF;

void* data = nullptr;
HRESULT hr = dst->Lock(0, size, &data, D3DLOCK_DISCARD);
if (FAILED(hr))
return D3DERR_INVALIDCALL;
auto iter = m_fvfTable.find(FVF);

if (iter == m_fvfTable.end()) {
decl = new D3D9VertexDecl(this, FVF);
m_fvfTable.insert(std::make_pair(FVF, decl));
}
else
decl = iter->second.ptr();
}

uint32_t offset = DestIndex * decl->GetSize();

auto slice = dst->GetBufferSlice<D3D9_COMMON_BUFFER_TYPE_REAL>();
slice = slice.subSlice(offset, slice.length() - offset);

EmitCs([this,
cDecl = ref(decl),
cVertexCount = VertexCount,
cStartIndex = SrcStartIndex,
cInstanceCount = GetInstanceCount(),
cBufferSlice = slice,
cIndexed = m_state.indices != nullptr
](DxvkContext* ctx) {
Rc<DxvkShader> shader = m_swvpEmulator.GetShaderModule(this, cDecl);

std::memset(data, 0, size);
auto drawInfo = GenerateDrawInfo(D3DPT_POINTLIST, cVertexCount, cInstanceCount);

dst->Unlock();
if (drawInfo.instanceCount != 1) {
drawInfo.instanceCount = 1;

Logger::warn("D3D9DeviceEx::ProcessVertices: instancing unsupported");
}

ApplyPrimitiveType(ctx, D3DPT_POINTLIST);

ctx->bindShader(VK_SHADER_STAGE_GEOMETRY_BIT, shader);
ctx->bindResourceBuffer(getSWVPBufferSlot(), cBufferSlice);
ctx->draw(
drawInfo.vertexCount, drawInfo.instanceCount,
cStartIndex, 0);
ctx->bindResourceBuffer(getSWVPBufferSlot(), DxvkBufferSlice());
ctx->bindShader(VK_SHADER_STAGE_GEOMETRY_BIT, nullptr);
});

if (dst->GetMapMode() == D3D9_COMMON_BUFFER_MAP_MODE_BUFFER) {
uint32_t copySize = VertexCount * decl->GetSize();

EmitCs([
cSrcBuffer = dst->GetBuffer<D3D9_COMMON_BUFFER_TYPE_REAL>(),
cDstBuffer = dst->GetBuffer<D3D9_COMMON_BUFFER_TYPE_MAPPING>(),
cOffset = offset,
cCopySize = copySize
](DxvkContext* ctx) {
ctx->copyBuffer(cDstBuffer, cOffset, cSrcBuffer, cOffset, cCopySize);
});
}

dst->SetReadLocked(true);

return D3D_OK;
}
@@ -3573,6 +3622,9 @@ namespace dxvk {
enabled.extVertexAttributeDivisor.vertexAttributeInstanceRateDivisor = supported.extVertexAttributeDivisor.vertexAttributeInstanceRateDivisor;
enabled.extVertexAttributeDivisor.vertexAttributeInstanceRateZeroDivisor = supported.extVertexAttributeDivisor.vertexAttributeInstanceRateZeroDivisor;

// ProcessVertices
enabled.core.features.vertexPipelineStoresAndAtomics = VK_TRUE;

// DXVK Meta
enabled.core.features.shaderStorageImageWriteWithoutFormat = VK_TRUE;
enabled.core.features.shaderStorageImageExtendedFormats = VK_TRUE;
@@ -4041,7 +4093,9 @@ namespace dxvk {
if (respectBounds && pResource->GetMapMode() == D3D9_COMMON_BUFFER_MAP_MODE_BUFFER && !(Flags & D3DLOCK_READONLY))
dirtyRangeOverlap = pResource->DirtyRange().overlap(pResource->LockRange());

bool skipWait = (Flags & D3DLOCK_NOOVERWRITE) || (Flags & D3DLOCK_READONLY) || !dirtyRangeOverlap;
bool readLocked = pResource->SetReadLocked(false);

bool skipWait = (Flags & D3DLOCK_NOOVERWRITE) || ( (Flags & D3DLOCK_READONLY) && !readLocked ) || !dirtyRangeOverlap;

// Wait until the resource is no longer in use
if (!skipWait) {
@@ -21,6 +21,7 @@

#include "d3d9_sampler.h"
#include "d3d9_fixed_function.h"
#include "d3d9_swvp_emu.h"

#include <vector>
#include <type_traits>
@@ -835,6 +836,7 @@ namespace dxvk {
DxvkCsChunkRef m_csChunk;

D3D9FFShaderModuleSet m_ffModules;
D3D9SWVPEmulator m_swvpEmulator;

DxvkCsChunkRef AllocCsChunk() {
DxvkCsChunk* chunk = m_csChunkPool.allocChunk(DxvkCsChunkFlag::SingleUse);
@@ -88,4 +88,6 @@ extern "C" WINUSERAPI WINBOOL WINAPI SetProcessDPIAware(VOID);
#endif

// This is the managed pool on D3D9Ex, it's just hidden!
#define D3DPOOL_MANAGED_EX D3DPOOL(6)
#define D3DPOOL_MANAGED_EX D3DPOOL(6)

using D3D9VertexElements = std::vector<D3DVERTEXELEMENT9>;

0 comments on commit 48c1df6

Please sign in to comment.
You can’t perform that action at this time.