Skip to content

Commit

Permalink
[d3d8] Implement Direct3D 8 Frontend
Browse files Browse the repository at this point in the history
Co-authored-by: WinterSnowfall <[email protected]>

## Config Changes

Co-authored-by: Blisto91 <[email protected]>
Co-authored-by: simifor <[email protected]>
  • Loading branch information
3 people authored Jul 7, 2024
1 parent ef0c6b6 commit 60e523b
Show file tree
Hide file tree
Showing 38 changed files with 5,069 additions and 10 deletions.
7 changes: 7 additions & 0 deletions .github/workflows/test-build-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ jobs:
Write-Output "VSDEVCMD=${installationPath}\Common7\Tools\VsDevCmd.bat" `
| Out-File -FilePath "${Env:GITHUB_ENV}" -Append
- name: Download D3D8 SDK Headers
shell: pwsh
run: |
Invoke-WebRequest -URI https://raw.githubusercontent.com/NovaRain/DXSDK_Collection/master/DXSDK_Aug2007/Include/d3d8.h -OutFile include/d3d8.h
Invoke-WebRequest -URI https://raw.githubusercontent.com/NovaRain/DXSDK_Collection/master/DXSDK_Aug2007/Include/d3d8types.h -OutFile include/d3d8types.h
Invoke-WebRequest -URI https://raw.githubusercontent.com/NovaRain/DXSDK_Collection/master/DXSDK_Aug2007/Include/d3d8caps.h -OutFile include/d3d8caps.h
- name: Build MSVC x86
shell: pwsh
run: |
Expand Down
1 change: 1 addition & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
Copyright (c) 2017 Philip Rebohle
Copyright (c) 2019 Joshua Ashton
Copyright (c) 2023 Jeffrey Ellison

zlib/libpng license

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# DXVK

A Vulkan-based translation layer for Direct3D 9/10/11 which allows running 3D applications on Linux using Wine.
A Vulkan-based translation layer for Direct3D 8/9/10/11 which allows running 3D applications on Linux using Wine.

For the current status of the project, please refer to the [project wiki](https://github.com/doitsujin/dxvk/wiki).

Expand Down
26 changes: 26 additions & 0 deletions dxvk.conf
Original file line number Diff line number Diff line change
Expand Up @@ -709,3 +709,29 @@
# - True/False

# d3d9.countLosableResources = True

# Use NVIDIA Shadow Buffers
#
# Vendor behavior for GeForce3 and GeForce4 cards that allows
# sampling depth textures with non-normalized Z coordinates
# and applies hardware shadow filtering.
#
# Supported values:
# - True/False

# d3d8.useShadowBuffers = False


# MANAGED Buffer Placement
#
# Remap some DEFAULT pool vertex and index buffers to the MANAGED pool to improve
# performance by avoiding waiting for games that frequently lock (large) buffers.
#
# This implicitly disables direct buffer mapping. Some applications may need this option
# disabled for certain (smaller) buffers to keep from overwriting in-use buffer regions.
#
# Supported values:
# - True/False
# - Any non-negative integer - sets the minimum size in bytes for a buffer to be MANAGED

# d3d8.managedBufferPlacement = True
1 change: 1 addition & 0 deletions meson_options.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
option('enable_dxgi', type : 'boolean', value : true, description: 'Build DXGI')
option('enable_d3d8', type : 'boolean', value : true, description: 'Build D3D8')
option('enable_d3d9', type : 'boolean', value : true, description: 'Build D3D9')
option('enable_d3d10', type : 'boolean', value : true, description: 'Build D3D10')
option('enable_d3d11', type : 'boolean', value : true, description: 'Build D3D11')
Expand Down
3 changes: 3 additions & 0 deletions src/d3d8/d3d8.def
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
LIBRARY D3D8.DLL
EXPORTS
Direct3DCreate8 @ 5
7 changes: 7 additions & 0 deletions src/d3d8/d3d8.sym
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
global:
Direct3DCreate8;

local:
*;
};
239 changes: 239 additions & 0 deletions src/d3d8/d3d8_batch.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
#pragma once

#include "d3d8_include.h"
#include "d3d8_buffer.h"
#include "d3d8_format.h"

#include <vector>
#include <cstdint>
#include <climits>

namespace dxvk {

inline constexpr size_t D3DPT_COUNT = size_t(D3DPT_TRIANGLEFAN) + 1;
inline constexpr D3DPRIMITIVETYPE D3DPT_INVALID = D3DPRIMITIVETYPE(0);

// Vertex buffer that can handle many tiny locks while
// still maintaing the lock ordering of direct-mapped buffers.
class D3D8BatchBuffer final : public D3D8VertexBuffer {
public:
D3D8BatchBuffer(
D3D8Device* pDevice,
D3DPOOL Pool,
DWORD Usage,
UINT Length,
DWORD FVF)
: D3D8VertexBuffer(pDevice, nullptr, Pool, Usage)
, m_data(Length)
, m_fvf(FVF) {
}

HRESULT STDMETHODCALLTYPE Lock(
UINT OffsetToLock,
UINT SizeToLock,
BYTE** ppbData,
DWORD Flags) {
*ppbData = m_data.data() + OffsetToLock;
return D3D_OK;
}

HRESULT STDMETHODCALLTYPE Unlock() {
return D3D_OK;
}

HRESULT STDMETHODCALLTYPE GetDesc(D3DVERTEXBUFFER_DESC* pDesc) {
pDesc->Format = D3DFMT_VERTEXDATA;
pDesc->Type = D3DRTYPE_VERTEXBUFFER;
pDesc->Usage = m_usage;
pDesc->Pool = m_pool;
pDesc->Size = m_data.size();
pDesc->FVF = m_fvf;
return D3D_OK;
}

void STDMETHODCALLTYPE PreLoad() {
}

const void* GetPtr(UINT byteOffset = 0) const {
return m_data.data() + byteOffset;
}

UINT Size() const {
return m_data.size();
}

private:
std::vector<BYTE> m_data;
DWORD m_fvf;
};


// Main handler for batching D3D8 draw calls.
class D3D8Batcher {

struct Batch {
D3DPRIMITIVETYPE PrimitiveType = D3DPT_INVALID;
std::vector<uint16_t> Indices;
UINT Offset = 0;
UINT MinVertex = UINT_MAX;
UINT MaxVertex = 0;
UINT PrimitiveCount = 0;
UINT DrawCallCount = 0;
};

public:
D3D8Batcher(D3D8Device* pDevice8, Com<d3d9::IDirect3DDevice9>&& pDevice9)
: m_device8(pDevice8)
, m_device(std::move(pDevice9)) {
}

inline D3D8BatchBuffer* CreateVertexBuffer(UINT Length, DWORD Usage, DWORD FVF, D3DPOOL Pool) {
return ref(new D3D8BatchBuffer(m_device8, Pool, Usage, Length, FVF));
}

inline void StateChange() {
if (likely(m_batches.empty()))
return;
for (auto& draw : m_batches) {

if (draw.PrimitiveType == D3DPT_INVALID)
continue;

for (auto& index : draw.Indices)
index -= draw.MinVertex;

m_device->DrawIndexedPrimitiveUP(
d3d9::D3DPRIMITIVETYPE(draw.PrimitiveType),
0,
draw.MaxVertex - draw.MinVertex,
draw.PrimitiveCount,
draw.Indices.data(),
d3d9::D3DFMT_INDEX16,
m_stream->GetPtr(draw.MinVertex * m_stride),
m_stride);

m_device->SetStreamSource(0, D3D8VertexBuffer::GetD3D9Nullable(m_stream), 0, m_stride);
m_device->SetIndices(D3D8IndexBuffer::GetD3D9Nullable(m_indices));

draw.PrimitiveType = D3DPRIMITIVETYPE(0);
draw.Offset = 0;
draw.MinVertex = UINT_MAX;
draw.MaxVertex = 0;
draw.PrimitiveCount = 0;
draw.DrawCallCount = 0;
}
}

inline void EndFrame() {
// Nothing to be done.
}

inline HRESULT DrawPrimitive(
D3DPRIMITIVETYPE PrimitiveType,
UINT StartVertex,
UINT PrimitiveCount) {

// None of this linestrip or fan malarkey
D3DPRIMITIVETYPE batchedPrimType = PrimitiveType;
switch (PrimitiveType) {
case D3DPT_LINESTRIP: batchedPrimType = D3DPT_LINELIST; break;
case D3DPT_TRIANGLEFAN: batchedPrimType = D3DPT_TRIANGLELIST; break;
default: break;
}

Batch* batch = &m_batches[size_t(batchedPrimType)];
batch->PrimitiveType = batchedPrimType;

//UINT vertices = GetVertexCount8(PrimitiveType, PrimitiveCount);

switch (PrimitiveType) {
case D3DPT_POINTLIST:
batch->Indices.resize(batch->Offset + PrimitiveCount);
for (UINT i = 0; i < PrimitiveCount; i++)
batch->Indices[batch->Offset++] = (StartVertex + i);
break;
case D3DPT_LINELIST:
batch->Indices.resize(batch->Offset + PrimitiveCount * 2);
for (UINT i = 0; i < PrimitiveCount; i++) {
batch->Indices[batch->Offset++] = (StartVertex + i * 2 + 0);
batch->Indices[batch->Offset++] = (StartVertex + i * 2 + 1);
}
break;
case D3DPT_LINESTRIP:
batch->Indices.resize(batch->Offset + PrimitiveCount * 2);
for (UINT i = 0; i < PrimitiveCount; i++) {
batch->Indices[batch->Offset++] = (StartVertex + i + 0);
batch->Indices[batch->Offset++] = (StartVertex + i + 1);
}
break;
case D3DPT_TRIANGLELIST:
batch->Indices.resize(batch->Offset + PrimitiveCount * 3);
for (UINT i = 0; i < PrimitiveCount; i++) {
batch->Indices[batch->Offset++] = (StartVertex + i * 3 + 0);
batch->Indices[batch->Offset++] = (StartVertex + i * 3 + 1);
batch->Indices[batch->Offset++] = (StartVertex + i * 3 + 2);
}
break;
case D3DPT_TRIANGLESTRIP:
// Join with degenerate triangle
// 1 2 3, 3 4, 4 5 6
batch->Indices.resize(batch->Offset + PrimitiveCount + 2);
if (batch->Offset > 0) {
batch->Indices[batch->Offset + 1] = batch->Indices[batch->Offset-2];
batch->Indices[batch->Offset += 2] = StartVertex;
}
for (UINT i = 0; i < PrimitiveCount; i++) {
batch->Indices[batch->Offset++] = (StartVertex + i + 0);
}
break;
// 1 2 3 4 5 6 7 -> 1 2 3, 1 3 4, 1 4 5, 1 5 6, 1 6 7
case D3DPT_TRIANGLEFAN:
batch->Indices.resize(batch->Offset + PrimitiveCount * 3);
for (UINT i = 0; i < PrimitiveCount; i++) {
batch->Indices[batch->Offset++] = (StartVertex + 0);
batch->Indices[batch->Offset++] = (StartVertex + i + 1);
batch->Indices[batch->Offset++] = (StartVertex + i + 2);
}
break;
default:
return D3DERR_INVALIDCALL;
}
batch->MinVertex = std::min(batch->MinVertex, StartVertex);
if (!batch->Indices.empty())
batch->MaxVertex = std::max(batch->MaxVertex, UINT(batch->Indices.back() + 1));
batch->PrimitiveCount += PrimitiveCount;
batch->DrawCallCount++;
return D3D_OK;
}

inline void SetStream(UINT num, D3D8VertexBuffer* stream, UINT stride) {
if (unlikely(num != 0)) {
StateChange();
return;
}
if (unlikely(m_stream != stream || m_stride != stride)) {
StateChange();
m_stream = static_cast<D3D8BatchBuffer*>(stream);
m_stride = stride;
}
}

inline void SetIndices(D3D8IndexBuffer* indices, INT baseVertexIndex) {
if (m_indices != indices || m_baseVertexIndex != baseVertexIndex) {
StateChange();
m_indices = indices;
m_baseVertexIndex = baseVertexIndex;
}
}

private:
D3D8Device* m_device8;
Com<d3d9::IDirect3DDevice9> m_device;

D3D8BatchBuffer* m_stream = nullptr;
UINT m_stride = 0;
D3D8IndexBuffer* m_indices = nullptr;
INT m_baseVertexIndex = 0;
std::array<Batch, D3DPT_COUNT> m_batches;
};
}
Loading

0 comments on commit 60e523b

Please sign in to comment.