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