Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/GPU/D3D11/DrawEngineD3D11.cpp
3186 views
1
// Copyright (c) 2012- PPSSPP Project.
2
3
// This program is free software: you can redistribute it and/or modify
4
// it under the terms of the GNU General Public License as published by
5
// the Free Software Foundation, version 2.0 or later versions.
6
7
// This program is distributed in the hope that it will be useful,
8
// but WITHOUT ANY WARRANTY; without even the implied warranty of
9
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
// GNU General Public License 2.0 for more details.
11
12
// A copy of the GPL 2.0 should have been included with the program.
13
// If not, see http://www.gnu.org/licenses/
14
15
// Official git repository and contact information can be found at
16
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
17
18
#include <wrl/client.h>
19
20
#include "Common/Log.h"
21
#include "Common/Profiler/Profiler.h"
22
23
#include "Core/Config.h"
24
25
#include "GPU/GPUState.h"
26
#include "GPU/ge_constants.h"
27
28
#include "GPU/Common/SplineCommon.h"
29
#include "GPU/Common/TransformCommon.h"
30
#include "GPU/Common/VertexDecoderCommon.h"
31
#include "GPU/Common/SoftwareTransformCommon.h"
32
#include "GPU/D3D11/FramebufferManagerD3D11.h"
33
#include "GPU/D3D11/TextureCacheD3D11.h"
34
#include "GPU/D3D11/DrawEngineD3D11.h"
35
#include "GPU/D3D11/ShaderManagerD3D11.h"
36
37
using namespace Microsoft::WRL;
38
39
const D3D11_PRIMITIVE_TOPOLOGY d3d11prim[8] = {
40
D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST, // Points are expanded to triangles.
41
D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST, // Lines are expanded to triangles too.
42
D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST, // Lines are expanded to triangles too.
43
D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST,
44
D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP,
45
D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST, // Fans not supported
46
D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST, // Need expansion - though we could do it with geom shaders in most cases
47
};
48
49
enum {
50
VERTEX_PUSH_SIZE = 1024 * 1024 * 16,
51
INDEX_PUSH_SIZE = 1024 * 1024 * 4,
52
};
53
54
static const D3D11_INPUT_ELEMENT_DESC TransformedVertexElements[] = {
55
{ "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, offsetof(TransformedVertex, pos), D3D11_INPUT_PER_VERTEX_DATA, 0 },
56
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, offsetof(TransformedVertex, uv), D3D11_INPUT_PER_VERTEX_DATA, 0 },
57
{ "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, offsetof(TransformedVertex, color0), D3D11_INPUT_PER_VERTEX_DATA, 0 },
58
{ "COLOR", 1, DXGI_FORMAT_R8G8B8A8_UNORM, 0, offsetof(TransformedVertex, color1), D3D11_INPUT_PER_VERTEX_DATA, 0 },
59
{ "NORMAL", 0, DXGI_FORMAT_R32_FLOAT, 0, offsetof(TransformedVertex, fog), D3D11_INPUT_PER_VERTEX_DATA, 0 },
60
};
61
62
DrawEngineD3D11::DrawEngineD3D11(Draw::DrawContext *draw, ID3D11Device *device, ID3D11DeviceContext *context)
63
: draw_(draw),
64
device_(device),
65
context_(context),
66
inputLayoutMap_(32),
67
blendCache_(32),
68
blendCache1_(32),
69
depthStencilCache_(64),
70
rasterCache_(4) {
71
device1_ = (ID3D11Device1 *)draw->GetNativeObject(Draw::NativeObject::DEVICE_EX);
72
context1_ = (ID3D11DeviceContext1 *)draw->GetNativeObject(Draw::NativeObject::CONTEXT_EX);
73
decOptions_.expandAllWeightsToFloat = true;
74
decOptions_.expand8BitNormalsToFloat = true;
75
76
InitDeviceObjects();
77
}
78
79
DrawEngineD3D11::~DrawEngineD3D11() {
80
DestroyDeviceObjects();
81
}
82
83
void DrawEngineD3D11::InitDeviceObjects() {
84
pushVerts_ = new PushBufferD3D11(device_, VERTEX_PUSH_SIZE, D3D11_BIND_VERTEX_BUFFER);
85
pushInds_ = new PushBufferD3D11(device_, INDEX_PUSH_SIZE, D3D11_BIND_INDEX_BUFFER);
86
87
tessDataTransferD3D11 = new TessellationDataTransferD3D11(context_, device_);
88
tessDataTransfer = tessDataTransferD3D11;
89
90
draw_->SetInvalidationCallback(std::bind(&DrawEngineD3D11::Invalidate, this, std::placeholders::_1));
91
}
92
93
void DrawEngineD3D11::DestroyDeviceObjects() {
94
if (draw_) {
95
draw_->SetInvalidationCallback(InvalidationCallback());
96
}
97
98
ClearInputLayoutMap();
99
delete tessDataTransferD3D11;
100
tessDataTransferD3D11 = nullptr;
101
tessDataTransfer = nullptr;
102
delete pushVerts_;
103
delete pushInds_;
104
pushVerts_ = nullptr;
105
pushInds_ = nullptr;
106
107
// Clear state caches.
108
blendCache_.Iterate([&](const uint64_t &key, ID3D11BlendState *state) {
109
state->Release();
110
});
111
blendCache_.Clear();
112
blendCache1_.Iterate([&](const uint64_t &key, ID3D11BlendState1 *state) {
113
state->Release();
114
});
115
blendCache1_.Clear();
116
depthStencilCache_.Iterate([&](const uint64_t &key, ID3D11DepthStencilState *state) {
117
state->Release();
118
});
119
depthStencilCache_.Clear();
120
rasterCache_.Iterate([&](const uint32_t &key, ID3D11RasterizerState *state) {
121
state->Release();
122
});
123
rasterCache_.Clear();
124
inputLayoutMap_.Iterate([&](const InputLayoutKey &key, ID3D11InputLayout *state) {
125
state->Release();
126
});
127
inputLayoutMap_.Clear();
128
129
blendState_ = nullptr;
130
blendState1_ = nullptr;
131
rasterState_ = nullptr;
132
depthStencilState_ = nullptr;
133
}
134
135
void DrawEngineD3D11::DeviceLost() {
136
DestroyDeviceObjects();
137
draw_ = nullptr;
138
}
139
140
void DrawEngineD3D11::DeviceRestore(Draw::DrawContext *draw) {
141
draw_ = draw;
142
InitDeviceObjects();
143
}
144
145
void DrawEngineD3D11::ClearInputLayoutMap() {
146
inputLayoutMap_.Iterate([&](const InputLayoutKey &key, ID3D11InputLayout *il) {
147
il->Release();
148
});
149
inputLayoutMap_.Clear();
150
}
151
152
void DrawEngineD3D11::NotifyConfigChanged() {
153
DrawEngineCommon::NotifyConfigChanged();
154
ClearInputLayoutMap();
155
}
156
157
struct DeclTypeInfo {
158
DXGI_FORMAT type;
159
const char * name;
160
};
161
162
static const DeclTypeInfo VComp[] = {
163
{ DXGI_FORMAT_UNKNOWN, "NULL" }, // DEC_NONE,
164
{ DXGI_FORMAT_R32_FLOAT, "D3DDECLTYPE_FLOAT1 " }, // DEC_FLOAT_1,
165
{ DXGI_FORMAT_R32G32_FLOAT, "D3DDECLTYPE_FLOAT2 " }, // DEC_FLOAT_2,
166
{ DXGI_FORMAT_R32G32B32_FLOAT, "D3DDECLTYPE_FLOAT3 " }, // DEC_FLOAT_3,
167
{ DXGI_FORMAT_R32G32B32A32_FLOAT, "D3DDECLTYPE_FLOAT4 " }, // DEC_FLOAT_4,
168
169
{ DXGI_FORMAT_R8G8B8A8_SNORM, "UNUSED" }, // DEC_S8_3,
170
171
{ DXGI_FORMAT_R16G16B16A16_SNORM, "D3DDECLTYPE_SHORT4N " }, // DEC_S16_3,
172
{ DXGI_FORMAT_R8G8B8A8_UNORM, "D3DDECLTYPE_UBYTE4N " }, // DEC_U8_1,
173
{ DXGI_FORMAT_R8G8B8A8_UNORM, "D3DDECLTYPE_UBYTE4N " }, // DEC_U8_2,
174
{ DXGI_FORMAT_R8G8B8A8_UNORM, "D3DDECLTYPE_UBYTE4N " }, // DEC_U8_3,
175
{ DXGI_FORMAT_R8G8B8A8_UNORM, "D3DDECLTYPE_UBYTE4N " }, // DEC_U8_4,
176
177
{ DXGI_FORMAT_UNKNOWN, "UNUSED_DEC_U16_1" }, // DEC_U16_1,
178
{ DXGI_FORMAT_UNKNOWN, "UNUSED_DEC_U16_2" }, // DEC_U16_2,
179
{ DXGI_FORMAT_R16G16B16A16_UNORM ,"D3DDECLTYPE_USHORT4N "}, // DEC_U16_3,
180
{ DXGI_FORMAT_R16G16B16A16_UNORM ,"D3DDECLTYPE_USHORT4N "}, // DEC_U16_4,
181
};
182
183
static void VertexAttribSetup(D3D11_INPUT_ELEMENT_DESC * VertexElement, u8 fmt, u8 offset, const char *semantic, u8 semantic_index = 0) {
184
memset(VertexElement, 0, sizeof(D3D11_INPUT_ELEMENT_DESC));
185
VertexElement->AlignedByteOffset = offset;
186
VertexElement->Format = VComp[fmt].type;
187
VertexElement->SemanticName = semantic;
188
VertexElement->SemanticIndex = semantic_index;
189
}
190
191
HRESULT DrawEngineD3D11::SetupDecFmtForDraw(D3D11VertexShader *vshader, const DecVtxFormat &decFmt, u32 pspFmt, ID3D11InputLayout **ppInputLayout) {
192
// TODO: Instead of one for each vshader, we can reduce it to one for each type of shader
193
// that reads TEXCOORD or not, etc. Not sure if worth it.
194
const InputLayoutKey key{ vshader, decFmt.id };
195
ID3D11InputLayout *inputLayout;
196
if (inputLayoutMap_.Get(key, &inputLayout)) {
197
*ppInputLayout = inputLayout;
198
return S_OK;
199
} else {
200
D3D11_INPUT_ELEMENT_DESC VertexElements[8];
201
D3D11_INPUT_ELEMENT_DESC *VertexElement = &VertexElements[0];
202
203
// Vertices Elements orders
204
// WEIGHT
205
if (decFmt.w0fmt != 0) {
206
VertexAttribSetup(VertexElement, decFmt.w0fmt, decFmt.w0off, "TEXCOORD", 1);
207
VertexElement++;
208
}
209
210
if (decFmt.w1fmt != 0) {
211
VertexAttribSetup(VertexElement, decFmt.w1fmt, decFmt.w1off, "TEXCOORD", 2);
212
VertexElement++;
213
}
214
215
// TC
216
if (decFmt.uvfmt != 0) {
217
VertexAttribSetup(VertexElement, decFmt.uvfmt, decFmt.uvoff, "TEXCOORD", 0);
218
VertexElement++;
219
}
220
221
// COLOR
222
if (decFmt.c0fmt != 0) {
223
VertexAttribSetup(VertexElement, decFmt.c0fmt, decFmt.c0off, "COLOR", 0);
224
VertexElement++;
225
}
226
// Never used ?
227
if (decFmt.c1fmt != 0) {
228
VertexAttribSetup(VertexElement, decFmt.c1fmt, decFmt.c1off, "COLOR", 1);
229
VertexElement++;
230
}
231
232
// NORMAL
233
if (decFmt.nrmfmt != 0) {
234
VertexAttribSetup(VertexElement, decFmt.nrmfmt, decFmt.nrmoff, "NORMAL", 0);
235
VertexElement++;
236
}
237
238
// POSITION
239
// Always
240
VertexAttribSetup(VertexElement, DecVtxFormat::PosFmt(), decFmt.posoff, "POSITION", 0);
241
VertexElement++;
242
243
// Create declaration
244
HRESULT hr = device_->CreateInputLayout(VertexElements, VertexElement - VertexElements, vshader->bytecode().data(), vshader->bytecode().size(), &inputLayout);
245
if (FAILED(hr)) {
246
ERROR_LOG(Log::G3D, "Failed to create input layout!");
247
*ppInputLayout = nullptr;
248
return hr;
249
}
250
251
// Add it to map
252
inputLayoutMap_.Insert(key, inputLayout);
253
*ppInputLayout = inputLayout;
254
return hr;
255
}
256
}
257
258
void DrawEngineD3D11::BeginFrame() {
259
DrawEngineCommon::BeginFrame();
260
261
pushVerts_->Reset();
262
pushInds_->Reset();
263
264
lastRenderStepId_ = -1;
265
}
266
267
// In D3D, we're synchronous and state carries over so all we reset here on a new step is the viewport/scissor.
268
void DrawEngineD3D11::Invalidate(InvalidationCallbackFlags flags) {
269
if (flags & InvalidationCallbackFlags::RENDER_PASS_STATE) {
270
gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS);
271
}
272
}
273
274
void DrawEngineD3D11::Flush() {
275
if (!numDrawVerts_) {
276
return;
277
}
278
bool textureNeedsApply = false;
279
if (gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS) && !gstate.isModeClear() && gstate.isTextureMapEnabled()) {
280
textureCache_->SetTexture();
281
gstate_c.Clean(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS);
282
textureNeedsApply = true;
283
} else if (gstate.getTextureAddress(0) == (gstate.getFrameBufRawAddress() | 0x04000000)) {
284
// This catches the case of clearing a texture. (#10957)
285
gstate_c.Dirty(DIRTY_TEXTURE_IMAGE);
286
}
287
288
// This is not done on every drawcall, we collect vertex data
289
// until critical state changes. That's when we draw (flush).
290
291
GEPrimitiveType prim = prevPrim_;
292
293
// Always use software for flat shading to fix the provoking index.
294
bool tess = gstate_c.submitType == SubmitType::HW_BEZIER || gstate_c.submitType == SubmitType::HW_SPLINE;
295
bool useHWTransform = CanUseHardwareTransform(prim) && (tess || gstate.getShadeMode() != GE_SHADE_FLAT);
296
297
if (useHWTransform) {
298
ID3D11Buffer *vb_ = nullptr;
299
ID3D11Buffer *ib_ = nullptr;
300
301
int vertexCount;
302
int maxIndex;
303
bool useElements;
304
DecodeVerts(dec_, decoded_);
305
DecodeIndsAndGetData(&prim, &vertexCount, &maxIndex, &useElements, false);
306
gpuStats.numUncachedVertsDrawn += vertexCount;
307
308
bool hasColor = (lastVType_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE;
309
if (gstate.isModeThrough()) {
310
gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && (hasColor || gstate.getMaterialAmbientA() == 255);
311
} else {
312
gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && ((hasColor && (gstate.materialupdate & 1)) || gstate.getMaterialAmbientA() == 255) && (!gstate.isLightingEnabled() || gstate.getAmbientA() == 255);
313
}
314
315
if (textureNeedsApply) {
316
textureCache_->ApplyTexture();
317
}
318
319
// Need to ApplyDrawState after ApplyTexture because depal can launch a render pass and that wrecks the state.
320
ApplyDrawState(prim);
321
ApplyDrawStateLate(true, dynState_.stencilRef);
322
323
D3D11VertexShader *vshader;
324
D3D11FragmentShader *fshader;
325
shaderManager_->GetShaders(prim, dec_->VertexType(), &vshader, &fshader, pipelineState_, useHWTransform, useHWTessellation_, decOptions_.expandAllWeightsToFloat, applySkinInDecode_);
326
ID3D11InputLayout *inputLayout;
327
SetupDecFmtForDraw(vshader, dec_->GetDecVtxFmt(), dec_->VertexType(), &inputLayout);
328
context_->PSSetShader(fshader->GetShader(), nullptr, 0);
329
context_->VSSetShader(vshader->GetShader(), nullptr, 0);
330
shaderManager_->UpdateUniforms(framebufferManager_->UseBufferedRendering());
331
shaderManager_->BindUniforms();
332
333
context_->IASetInputLayout(inputLayout);
334
UINT stride = dec_->GetDecVtxFmt().stride;
335
context_->IASetPrimitiveTopology(d3d11prim[prim]);
336
337
if (!vb_) {
338
// Push!
339
UINT vOffset;
340
int vSize = numDecodedVerts_ * dec_->GetDecVtxFmt().stride;
341
uint8_t *vptr = pushVerts_->BeginPush(context_, &vOffset, vSize);
342
memcpy(vptr, decoded_, vSize);
343
pushVerts_->EndPush(context_);
344
ID3D11Buffer *buf = pushVerts_->Buf();
345
context_->IASetVertexBuffers(0, 1, &buf, &stride, &vOffset);
346
if (useElements) {
347
UINT iOffset;
348
int iSize = 2 * vertexCount;
349
uint8_t *iptr = pushInds_->BeginPush(context_, &iOffset, iSize);
350
memcpy(iptr, decIndex_, iSize);
351
pushInds_->EndPush(context_);
352
context_->IASetIndexBuffer(pushInds_->Buf(), DXGI_FORMAT_R16_UINT, iOffset);
353
context_->DrawIndexed(vertexCount, 0, 0);
354
} else {
355
context_->Draw(vertexCount, 0);
356
}
357
} else {
358
UINT offset = 0;
359
context_->IASetVertexBuffers(0, 1, &vb_, &stride, &offset);
360
if (useElements) {
361
context_->IASetIndexBuffer(ib_, DXGI_FORMAT_R16_UINT, 0);
362
context_->DrawIndexed(vertexCount, 0, 0);
363
} else {
364
context_->Draw(vertexCount, 0);
365
}
366
}
367
if (useDepthRaster_) {
368
DepthRasterSubmitRaw(prim, dec_, dec_->VertexType(), vertexCount);
369
}
370
} else {
371
PROFILE_THIS_SCOPE("soft");
372
const VertexDecoder *swDec = dec_;
373
if (swDec->nweights != 0) {
374
u32 withSkinning = lastVType_ | (1 << 26);
375
if (withSkinning != lastVType_) {
376
swDec = GetVertexDecoder(withSkinning);
377
}
378
}
379
380
DecodeVerts(swDec, decoded_);
381
int vertexCount = DecodeInds();
382
383
bool hasColor = (lastVType_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE;
384
if (gstate.isModeThrough()) {
385
gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && (hasColor || gstate.getMaterialAmbientA() == 255);
386
} else {
387
gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && ((hasColor && (gstate.materialupdate & 1)) || gstate.getMaterialAmbientA() == 255) && (!gstate.isLightingEnabled() || gstate.getAmbientA() == 255);
388
}
389
390
gpuStats.numUncachedVertsDrawn += vertexCount;
391
prim = IndexGenerator::GeneralPrim((GEPrimitiveType)drawInds_[0].prim);
392
VERBOSE_LOG(Log::G3D, "Flush prim %i SW! %i verts in one go", prim, vertexCount);
393
394
u16 *inds = decIndex_;
395
SoftwareTransformResult result{};
396
SoftwareTransformParams params{};
397
params.decoded = decoded_;
398
params.transformed = transformed_;
399
params.transformedExpanded = transformedExpanded_;
400
params.fbman = framebufferManager_;
401
params.texCache = textureCache_;
402
params.allowClear = true;
403
params.allowSeparateAlphaClear = false; // D3D11 doesn't support separate alpha clears
404
params.flippedY = false;
405
params.usesHalfZ = true;
406
407
if (gstate.getShadeMode() == GE_SHADE_FLAT) {
408
// We need to rotate the index buffer to simulate a different provoking vertex.
409
// We do this before line expansion etc.
410
IndexBufferProvokingLastToFirst(prim, inds, vertexCount);
411
}
412
413
// We need correct viewport values in gstate_c already.
414
if (gstate_c.IsDirty(DIRTY_VIEWPORTSCISSOR_STATE)) {
415
ViewportAndScissor vpAndScissor;
416
ConvertViewportAndScissor(framebufferManager_->UseBufferedRendering(),
417
framebufferManager_->GetRenderWidth(), framebufferManager_->GetRenderHeight(),
418
framebufferManager_->GetTargetBufferWidth(), framebufferManager_->GetTargetBufferHeight(),
419
vpAndScissor);
420
UpdateCachedViewportState(vpAndScissor);
421
}
422
423
// At this point, rect and line primitives are still preserved as such. So, it's the best time to do software depth raster.
424
// We could piggyback on the viewport transform below, but it gets complicated since it's different per-backend. Which we really
425
// should clean up one day...
426
if (useDepthRaster_) {
427
DepthRasterPredecoded(prim, decoded_, numDecodedVerts_, swDec, vertexCount);
428
}
429
430
SoftwareTransform swTransform(params);
431
432
const Lin::Vec3 trans(gstate_c.vpXOffset, -gstate_c.vpYOffset, gstate_c.vpZOffset * 0.5f + 0.5f);
433
const Lin::Vec3 scale(gstate_c.vpWidthScale, -gstate_c.vpHeightScale, gstate_c.vpDepthScale * 0.5f);
434
swTransform.SetProjMatrix(gstate.projMatrix, gstate_c.vpWidth < 0, gstate_c.vpHeight < 0, trans, scale);
435
436
swTransform.Transform(prim, swDec->VertexType(), swDec->GetDecVtxFmt(), numDecodedVerts_, &result);
437
// Non-zero depth clears are unusual, but some drivers don't match drawn depth values to cleared values.
438
// Games sometimes expect exact matches (see #12626, for example) for equal comparisons.
439
if (result.action == SW_CLEAR && everUsedEqualDepth_ && gstate.isClearModeDepthMask() && result.depth > 0.0f && result.depth < 1.0f)
440
result.action = SW_NOT_READY;
441
442
if (textureNeedsApply) {
443
gstate_c.pixelMapped = result.pixelMapped;
444
textureCache_->ApplyTexture();
445
gstate_c.pixelMapped = false;
446
}
447
448
// Need to ApplyDrawState after ApplyTexture because depal can launch a render pass and that wrecks the state.
449
ApplyDrawState(prim);
450
451
if (result.action == SW_NOT_READY)
452
swTransform.BuildDrawingParams(prim, vertexCount, swDec->VertexType(), inds, RemainingIndices(inds), numDecodedVerts_, VERTEX_BUFFER_MAX, &result);
453
if (result.setSafeSize)
454
framebufferManager_->SetSafeSize(result.safeWidth, result.safeHeight);
455
456
ApplyDrawStateLate(result.setStencil, result.stencilValue);
457
458
if (result.action == SW_DRAW_INDEXED) {
459
D3D11VertexShader *vshader;
460
D3D11FragmentShader *fshader;
461
shaderManager_->GetShaders(prim, swDec->VertexType(), &vshader, &fshader, pipelineState_, false, false, decOptions_.expandAllWeightsToFloat, true);
462
context_->PSSetShader(fshader->GetShader(), nullptr, 0);
463
context_->VSSetShader(vshader->GetShader(), nullptr, 0);
464
shaderManager_->UpdateUniforms(framebufferManager_->UseBufferedRendering());
465
shaderManager_->BindUniforms();
466
467
// We really do need a vertex layout for each vertex shader (or at least check its ID bits for what inputs it uses)!
468
// Some vertex shaders ignore one of the inputs, and then the layout created from it will lack it, which will be a problem for others.
469
InputLayoutKey key{ vshader, 0xFFFFFFFF }; // Let's use 0xFFFFFFFF to signify TransformedVertex
470
ID3D11InputLayout *layout;
471
if (!inputLayoutMap_.Get(key, &layout)) {
472
ASSERT_SUCCESS(device_->CreateInputLayout(TransformedVertexElements, ARRAY_SIZE(TransformedVertexElements), vshader->bytecode().data(), vshader->bytecode().size(), &layout));
473
inputLayoutMap_.Insert(key, layout);
474
}
475
context_->IASetInputLayout(layout);
476
context_->IASetPrimitiveTopology(d3d11prim[prim]);
477
478
UINT stride = sizeof(TransformedVertex);
479
UINT vOffset = 0;
480
int vSize = numDecodedVerts_ * stride;
481
uint8_t *vptr = pushVerts_->BeginPush(context_, &vOffset, vSize);
482
memcpy(vptr, result.drawBuffer, vSize);
483
pushVerts_->EndPush(context_);
484
ID3D11Buffer *buf = pushVerts_->Buf();
485
context_->IASetVertexBuffers(0, 1, &buf, &stride, &vOffset);
486
UINT iOffset;
487
int iSize = sizeof(uint16_t) * result.drawNumTrans;
488
uint8_t *iptr = pushInds_->BeginPush(context_, &iOffset, iSize);
489
memcpy(iptr, inds, iSize);
490
pushInds_->EndPush(context_);
491
context_->IASetIndexBuffer(pushInds_->Buf(), DXGI_FORMAT_R16_UINT, iOffset);
492
context_->DrawIndexed(result.drawNumTrans, 0, 0);
493
} else if (result.action == SW_CLEAR) {
494
u32 clearColor = result.color;
495
float clearDepth = result.depth;
496
497
Draw::Aspect clearFlag = Draw::Aspect::NO_BIT;
498
499
if (gstate.isClearModeColorMask()) clearFlag |= Draw::Aspect::COLOR_BIT;
500
if (gstate.isClearModeAlphaMask()) clearFlag |= Draw::Aspect::STENCIL_BIT;
501
if (gstate.isClearModeDepthMask()) clearFlag |= Draw::Aspect::DEPTH_BIT;
502
503
uint8_t clearStencil = clearColor >> 24;
504
draw_->Clear(clearFlag, clearColor, clearDepth, clearStencil);
505
506
if (gstate_c.Use(GPU_USE_CLEAR_RAM_HACK) && gstate.isClearModeColorMask() && (gstate.isClearModeAlphaMask() || gstate_c.framebufFormat == GE_FORMAT_565)) {
507
int scissorX1 = gstate.getScissorX1();
508
int scissorY1 = gstate.getScissorY1();
509
int scissorX2 = gstate.getScissorX2() + 1;
510
int scissorY2 = gstate.getScissorY2() + 1;
511
framebufferManager_->ApplyClearToMemory(scissorX1, scissorY1, scissorX2, scissorY2, clearColor);
512
}
513
}
514
}
515
516
ResetAfterDrawInline();
517
framebufferManager_->SetColorUpdated(gstate_c.skipDrawReason);
518
gpuCommon_->NotifyFlush();
519
}
520
521
TessellationDataTransferD3D11::TessellationDataTransferD3D11(ID3D11DeviceContext *context, ID3D11Device *device)
522
: context_(context), device_(device) {
523
desc.Usage = D3D11_USAGE_DYNAMIC;
524
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
525
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
526
desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
527
}
528
529
TessellationDataTransferD3D11::~TessellationDataTransferD3D11() {
530
}
531
532
void TessellationDataTransferD3D11::SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Spline::Weight2D &weights) {
533
struct TessData {
534
float pos[3]; float pad1;
535
float uv[2]; float pad2[2];
536
float color[4];
537
};
538
539
int size = size_u * size_v;
540
541
if (prevSize < size || !buf[0]) {
542
prevSize = size;
543
buf[0].Reset();
544
view[0].Reset();
545
546
desc.ByteWidth = size * sizeof(TessData);
547
desc.StructureByteStride = sizeof(TessData);
548
device_->CreateBuffer(&desc, nullptr, &buf[0]);
549
if (buf[0])
550
device_->CreateShaderResourceView(buf[0].Get(), nullptr, &view[0]);
551
if (!buf[0] || !view[0])
552
return;
553
context_->VSSetShaderResources(0, 1, view[0].GetAddressOf());
554
}
555
D3D11_MAPPED_SUBRESOURCE map{};
556
HRESULT hr = context_->Map(buf[0].Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
557
if (FAILED(hr))
558
return;
559
uint8_t *data = (uint8_t *)map.pData;
560
561
float *pos = (float *)(data);
562
float *tex = (float *)(data + offsetof(TessData, uv));
563
float *col = (float *)(data + offsetof(TessData, color));
564
int stride = sizeof(TessData) / sizeof(float);
565
566
CopyControlPoints(pos, tex, col, stride, stride, stride, points, size, vertType);
567
568
context_->Unmap(buf[0].Get(), 0);
569
570
using Spline::Weight;
571
572
// Weights U
573
if (prevSizeWU < weights.size_u || !buf[1]) {
574
prevSizeWU = weights.size_u;
575
buf[1].Reset();
576
view[1].Reset();
577
578
desc.ByteWidth = weights.size_u * sizeof(Weight);
579
desc.StructureByteStride = sizeof(Weight);
580
device_->CreateBuffer(&desc, nullptr, &buf[1]);
581
if (buf[1])
582
device_->CreateShaderResourceView(buf[1].Get(), nullptr, &view[1]);
583
if (!buf[1] || !view[1])
584
return;
585
context_->VSSetShaderResources(1, 1, view[1].GetAddressOf());
586
}
587
hr = context_->Map(buf[1].Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
588
if (SUCCEEDED(hr))
589
memcpy(map.pData, weights.u, weights.size_u * sizeof(Weight));
590
context_->Unmap(buf[1].Get(), 0);
591
592
// Weights V
593
if (prevSizeWV < weights.size_v) {
594
prevSizeWV = weights.size_v;
595
buf[2].Reset();
596
view[2].Reset();
597
598
desc.ByteWidth = weights.size_v * sizeof(Weight);
599
desc.StructureByteStride = sizeof(Weight);
600
device_->CreateBuffer(&desc, nullptr, &buf[2]);
601
if (buf[2])
602
device_->CreateShaderResourceView(buf[2].Get(), nullptr, &view[2]);
603
if (!buf[2] || !view[2])
604
return;
605
context_->VSSetShaderResources(2, 1, view[2].GetAddressOf());
606
}
607
hr = context_->Map(buf[2].Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
608
if (SUCCEEDED(hr))
609
memcpy(map.pData, weights.v, weights.size_v * sizeof(Weight));
610
context_->Unmap(buf[2].Get(), 0);
611
}
612
613