Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/GPU/GLES/DrawEngineGLES.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 <algorithm>
19
20
#include "Common/LogReporting.h"
21
22
#include "Common/GPU/OpenGL/GLDebugLog.h"
23
#include "Common/Profiler/Profiler.h"
24
25
#include "GPU/GPUState.h"
26
#include "GPU/ge_constants.h"
27
28
#include "GPU/Common/SplineCommon.h"
29
#include "GPU/Common/VertexDecoderCommon.h"
30
#include "GPU/Common/SoftwareTransformCommon.h"
31
#include "GPU/GLES/DrawEngineGLES.h"
32
#include "GPU/GLES/ShaderManagerGLES.h"
33
#include "GPU/GLES/GPU_GLES.h"
34
#include "GPU/GLES/FramebufferManagerGLES.h"
35
36
static const GLuint glprim[8] = {
37
// Points, which are expanded to triangles.
38
GL_TRIANGLES,
39
// Lines and line strips, which are also expanded to triangles.
40
GL_TRIANGLES,
41
GL_TRIANGLES,
42
GL_TRIANGLES,
43
GL_TRIANGLE_STRIP,
44
GL_TRIANGLE_FAN,
45
// Rectangles, which are expanded to triangles.
46
GL_TRIANGLES,
47
};
48
49
enum {
50
TRANSFORMED_VERTEX_BUFFER_SIZE = VERTEX_BUFFER_MAX * sizeof(TransformedVertex)
51
};
52
53
DrawEngineGLES::DrawEngineGLES(Draw::DrawContext *draw) : inputLayoutMap_(16), draw_(draw) {
54
render_ = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
55
56
decOptions_.expandAllWeightsToFloat = false;
57
decOptions_.expand8BitNormalsToFloat = false;
58
59
InitDeviceObjects();
60
61
tessDataTransferGLES = new TessellationDataTransferGLES(render_);
62
tessDataTransfer = tessDataTransferGLES;
63
}
64
65
DrawEngineGLES::~DrawEngineGLES() {
66
DestroyDeviceObjects();
67
68
delete tessDataTransferGLES;
69
}
70
71
void DrawEngineGLES::DeviceLost() {
72
DestroyDeviceObjects();
73
draw_ = nullptr;
74
render_ = nullptr;
75
}
76
77
void DrawEngineGLES::DeviceRestore(Draw::DrawContext *draw) {
78
draw_ = draw;
79
render_ = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
80
InitDeviceObjects();
81
}
82
83
void DrawEngineGLES::InitDeviceObjects() {
84
_assert_msg_(render_ != nullptr, "Render manager must be set");
85
86
for (int i = 0; i < GLRenderManager::MAX_INFLIGHT_FRAMES; i++) {
87
frameData_[i].pushVertex = render_->CreatePushBuffer(i, GL_ARRAY_BUFFER, 2048 * 1024, "game_vertex");
88
frameData_[i].pushIndex = render_->CreatePushBuffer(i, GL_ELEMENT_ARRAY_BUFFER, 256 * 1024, "game_index");
89
}
90
91
int stride = sizeof(TransformedVertex);
92
std::vector<GLRInputLayout::Entry> entries;
93
entries.push_back({ ATTR_POSITION, 4, GL_FLOAT, GL_FALSE, offsetof(TransformedVertex, x) });
94
entries.push_back({ ATTR_TEXCOORD, 3, GL_FLOAT, GL_FALSE, offsetof(TransformedVertex, u) });
95
entries.push_back({ ATTR_COLOR0, 4, GL_UNSIGNED_BYTE, GL_TRUE, offsetof(TransformedVertex, color0) });
96
entries.push_back({ ATTR_COLOR1, 3, GL_UNSIGNED_BYTE, GL_TRUE, offsetof(TransformedVertex, color1) });
97
entries.push_back({ ATTR_NORMAL, 1, GL_FLOAT, GL_FALSE, offsetof(TransformedVertex, fog) });
98
softwareInputLayout_ = render_->CreateInputLayout(entries, stride);
99
100
draw_->SetInvalidationCallback(std::bind(&DrawEngineGLES::Invalidate, this, std::placeholders::_1));
101
}
102
103
void DrawEngineGLES::DestroyDeviceObjects() {
104
if (!draw_) {
105
return;
106
}
107
draw_->SetInvalidationCallback(InvalidationCallback());
108
109
// Beware: this could be called twice in a row, sometimes.
110
for (int i = 0; i < GLRenderManager::MAX_INFLIGHT_FRAMES; i++) {
111
if (!frameData_[i].pushVertex && !frameData_[i].pushIndex)
112
continue;
113
114
if (frameData_[i].pushVertex)
115
render_->DeletePushBuffer(frameData_[i].pushVertex);
116
if (frameData_[i].pushIndex)
117
render_->DeletePushBuffer(frameData_[i].pushIndex);
118
frameData_[i].pushVertex = nullptr;
119
frameData_[i].pushIndex = nullptr;
120
}
121
122
if (softwareInputLayout_)
123
render_->DeleteInputLayout(softwareInputLayout_);
124
softwareInputLayout_ = nullptr;
125
126
ClearInputLayoutMap();
127
}
128
129
void DrawEngineGLES::ClearInputLayoutMap() {
130
inputLayoutMap_.Iterate([&](const uint32_t &key, GLRInputLayout *il) {
131
render_->DeleteInputLayout(il);
132
});
133
inputLayoutMap_.Clear();
134
}
135
136
void DrawEngineGLES::BeginFrame() {
137
DrawEngineCommon::BeginFrame();
138
139
FrameData &frameData = frameData_[render_->GetCurFrame()];
140
frameData.pushIndex->Begin();
141
frameData.pushVertex->Begin();
142
143
lastRenderStepId_ = -1;
144
}
145
146
void DrawEngineGLES::EndFrame() {
147
FrameData &frameData = frameData_[render_->GetCurFrame()];
148
frameData.pushIndex->End();
149
frameData.pushVertex->End();
150
tessDataTransferGLES->EndFrame();
151
}
152
153
struct GlTypeInfo {
154
u16 type;
155
u8 count;
156
u8 normalized;
157
};
158
159
static const GlTypeInfo GLComp[] = {
160
{0}, // DEC_NONE,
161
{GL_FLOAT, 1, GL_FALSE}, // DEC_FLOAT_1,
162
{GL_FLOAT, 2, GL_FALSE}, // DEC_FLOAT_2,
163
{GL_FLOAT, 3, GL_FALSE}, // DEC_FLOAT_3,
164
{GL_FLOAT, 4, GL_FALSE}, // DEC_FLOAT_4,
165
{GL_BYTE, 4, GL_TRUE}, // DEC_S8_3,
166
{GL_SHORT, 4, GL_TRUE},// DEC_S16_3,
167
{GL_UNSIGNED_BYTE, 1, GL_TRUE},// DEC_U8_1,
168
{GL_UNSIGNED_BYTE, 2, GL_TRUE},// DEC_U8_2,
169
{GL_UNSIGNED_BYTE, 3, GL_TRUE},// DEC_U8_3,
170
{GL_UNSIGNED_BYTE, 4, GL_TRUE},// DEC_U8_4,
171
{GL_UNSIGNED_SHORT, 1, GL_TRUE},// DEC_U16_1,
172
{GL_UNSIGNED_SHORT, 2, GL_TRUE},// DEC_U16_2,
173
{GL_UNSIGNED_SHORT, 3, GL_TRUE},// DEC_U16_3,
174
{GL_UNSIGNED_SHORT, 4, GL_TRUE},// DEC_U16_4,
175
};
176
177
static inline void VertexAttribSetup(int attrib, int fmt, int offset, std::vector<GLRInputLayout::Entry> &entries) {
178
if (fmt) {
179
const GlTypeInfo &type = GLComp[fmt];
180
GLRInputLayout::Entry entry;
181
entry.offset = offset;
182
entry.location = attrib;
183
entry.normalized = type.normalized;
184
entry.type = type.type;
185
entry.count = type.count;
186
entries.push_back(entry);
187
}
188
}
189
190
// TODO: Use VBO and get rid of the vertexData pointers - with that, we will supply only offsets
191
GLRInputLayout *DrawEngineGLES::SetupDecFmtForDraw(const DecVtxFormat &decFmt) {
192
uint32_t key = decFmt.id;
193
GLRInputLayout *inputLayout;
194
if (inputLayoutMap_.Get(key, &inputLayout)) {
195
return inputLayout;
196
}
197
198
std::vector<GLRInputLayout::Entry> entries;
199
VertexAttribSetup(ATTR_W1, decFmt.w0fmt, decFmt.w0off, entries);
200
VertexAttribSetup(ATTR_W2, decFmt.w1fmt, decFmt.w1off, entries);
201
VertexAttribSetup(ATTR_TEXCOORD, decFmt.uvfmt, decFmt.uvoff, entries);
202
VertexAttribSetup(ATTR_COLOR0, decFmt.c0fmt, decFmt.c0off, entries);
203
VertexAttribSetup(ATTR_COLOR1, decFmt.c1fmt, decFmt.c1off, entries);
204
VertexAttribSetup(ATTR_NORMAL, decFmt.nrmfmt, decFmt.nrmoff, entries);
205
VertexAttribSetup(ATTR_POSITION, DecVtxFormat::PosFmt(), decFmt.posoff, entries);
206
207
int stride = decFmt.stride;
208
inputLayout = render_->CreateInputLayout(entries, stride);
209
inputLayoutMap_.Insert(key, inputLayout);
210
return inputLayout;
211
}
212
213
// A new render step means we need to flush any dynamic state. Really, any state that is reset in
214
// GLQueueRunner::PerformRenderPass.
215
void DrawEngineGLES::Invalidate(InvalidationCallbackFlags flags) {
216
if (flags & InvalidationCallbackFlags::RENDER_PASS_STATE) {
217
// Dirty everything that has dynamic state that will need re-recording.
218
gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS);
219
}
220
}
221
222
void DrawEngineGLES::Flush() {
223
if (!numDrawVerts_) {
224
return;
225
}
226
PROFILE_THIS_SCOPE("flush");
227
FrameData &frameData = frameData_[render_->GetCurFrame()];
228
VShaderID vsid;
229
230
if (!render_->IsInRenderPass()) {
231
// Something went badly wrong. Try to survive by simply skipping the draw, though.
232
_dbg_assert_msg_(false, "Trying to DoFlush while not in a render pass. This is bad.");
233
// can't goto bail here, skips too many variable initializations. So let's wipe the most important stuff.
234
indexGen.Reset();
235
numDecodedVerts_ = 0;
236
numDrawVerts_ = 0;
237
numDrawInds_ = 0;
238
vertexCountInDrawCalls_ = 0;
239
decodeVertsCounter_ = 0;
240
decodeIndsCounter_ = 0;
241
return;
242
}
243
244
bool textureNeedsApply = false;
245
if (gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS) && !gstate.isModeClear() && gstate.isTextureMapEnabled()) {
246
textureCache_->SetTexture();
247
gstate_c.Clean(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS);
248
textureNeedsApply = true;
249
} else if (gstate.getTextureAddress(0) == (gstate.getFrameBufRawAddress() | 0x04000000)) {
250
// This catches the case of clearing a texture. (#10957)
251
gstate_c.Dirty(DIRTY_TEXTURE_IMAGE);
252
}
253
254
GEPrimitiveType prim = prevPrim_;
255
256
Shader *vshader = shaderManager_->ApplyVertexShader(CanUseHardwareTransform(prim), useHWTessellation_, dec_->VertexType(), decOptions_.expandAllWeightsToFloat, applySkinInDecode_ || !CanUseHardwareTransform(prim), &vsid);
257
258
GLRBuffer *vertexBuffer = nullptr;
259
GLRBuffer *indexBuffer = nullptr;
260
uint32_t vertexBufferOffset = 0;
261
uint32_t indexBufferOffset = 0;
262
263
if (vshader->UseHWTransform()) {
264
if (applySkinInDecode_ && (lastVType_ & GE_VTYPE_WEIGHT_MASK)) {
265
// If software skinning, we're predecoding into "decoded". So make sure we're done, then push that content.
266
DecodeVerts(dec_, decoded_);
267
uint32_t size = numDecodedVerts_ * dec_->GetDecVtxFmt().stride;
268
u8 *dest = (u8 *)frameData.pushVertex->Allocate(size, 4, &vertexBuffer, &vertexBufferOffset);
269
memcpy(dest, decoded_, size);
270
} else {
271
// Figure out how much pushbuffer space we need to allocate.
272
int vertsToDecode = ComputeNumVertsToDecode();
273
u8 *dest = (u8 *)frameData.pushVertex->Allocate(vertsToDecode * dec_->GetDecVtxFmt().stride, 4, &vertexBuffer, &vertexBufferOffset);
274
DecodeVerts(dec_, dest);
275
}
276
277
int vertexCount;
278
int maxIndex;
279
bool useElements;
280
DecodeVerts(dec_, decoded_);
281
DecodeIndsAndGetData(&prim, &vertexCount, &maxIndex, &useElements, false);
282
283
if (useElements) {
284
uint32_t esz = sizeof(uint16_t) * vertexCount;
285
void *dest = frameData.pushIndex->Allocate(esz, 2, &indexBuffer, &indexBufferOffset);
286
// TODO: When we need to apply an index offset, we can apply it directly when copying the indices here.
287
// Of course, minding the maximum value of 65535...
288
memcpy(dest, decIndex_, esz);
289
}
290
291
bool hasColor = (lastVType_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE;
292
if (gstate.isModeThrough()) {
293
gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && (hasColor || gstate.getMaterialAmbientA() == 255);
294
} else {
295
gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && ((hasColor && (gstate.materialupdate & 1)) || gstate.getMaterialAmbientA() == 255) && (!gstate.isLightingEnabled() || gstate.getAmbientA() == 255);
296
}
297
298
if (textureNeedsApply) {
299
textureCache_->ApplyTexture();
300
}
301
302
// Need to ApplyDrawState after ApplyTexture because depal can launch a render pass and that wrecks the state.
303
ApplyDrawState(prim);
304
ApplyDrawStateLate(false, 0);
305
306
LinkedShader *program = shaderManager_->ApplyFragmentShader(vsid, vshader, pipelineState_, framebufferManager_->UseBufferedRendering());
307
GLRInputLayout *inputLayout = SetupDecFmtForDraw(dec_->GetDecVtxFmt());
308
if (useElements) {
309
render_->DrawIndexed(inputLayout,
310
vertexBuffer, vertexBufferOffset,
311
indexBuffer, indexBufferOffset,
312
glprim[prim], vertexCount, GL_UNSIGNED_SHORT);
313
} else {
314
render_->Draw(
315
inputLayout, vertexBuffer, vertexBufferOffset,
316
glprim[prim], 0, vertexCount);
317
}
318
if (useDepthRaster_) {
319
DepthRasterSubmitRaw(prim, dec_, dec_->VertexType(), vertexCount);
320
}
321
} else {
322
PROFILE_THIS_SCOPE("soft");
323
const VertexDecoder *swDec = dec_;
324
if (swDec->nweights != 0) {
325
u32 withSkinning = lastVType_ | (1 << 26);
326
if (withSkinning != lastVType_) {
327
swDec = GetVertexDecoder(withSkinning);
328
}
329
}
330
DecodeVerts(swDec, decoded_);
331
int vertexCount = DecodeInds();
332
333
bool hasColor = (lastVType_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE;
334
if (gstate.isModeThrough()) {
335
gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && (hasColor || gstate.getMaterialAmbientA() == 255);
336
} else {
337
gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && ((hasColor && (gstate.materialupdate & 1)) || gstate.getMaterialAmbientA() == 255) && (!gstate.isLightingEnabled() || gstate.getAmbientA() == 255);
338
}
339
340
gpuStats.numUncachedVertsDrawn += vertexCount;
341
prim = IndexGenerator::GeneralPrim((GEPrimitiveType)drawInds_[0].prim);
342
343
u16 *inds = decIndex_;
344
SoftwareTransformResult result{};
345
// TODO: Keep this static? Faster than repopulating?
346
SoftwareTransformParams params{};
347
params.decoded = decoded_;
348
params.transformed = transformed_;
349
params.transformedExpanded = transformedExpanded_;
350
params.fbman = framebufferManager_;
351
params.texCache = textureCache_;
352
params.allowClear = true; // Clear in OpenGL respects scissor rects, so we'll use it.
353
params.allowSeparateAlphaClear = true;
354
params.flippedY = framebufferManager_->UseBufferedRendering();
355
params.usesHalfZ = false;
356
357
// We need correct viewport values in gstate_c already.
358
if (gstate_c.IsDirty(DIRTY_VIEWPORTSCISSOR_STATE)) {
359
ConvertViewportAndScissor(framebufferManager_->UseBufferedRendering(),
360
framebufferManager_->GetRenderWidth(), framebufferManager_->GetRenderHeight(),
361
framebufferManager_->GetTargetBufferWidth(), framebufferManager_->GetTargetBufferHeight(),
362
vpAndScissor_);
363
UpdateCachedViewportState(vpAndScissor_);
364
}
365
366
int maxIndex = numDecodedVerts_;
367
368
// TODO: Split up into multiple draw calls for GLES 2.0 where you can't guarantee support for more than 0x10000 verts.
369
if (gl_extensions.IsGLES && !gl_extensions.GLES3) {
370
constexpr int vertexCountLimit = 0x10000 / 3;
371
if (vertexCount > vertexCountLimit) {
372
WARN_LOG_REPORT_ONCE(manyVerts, Log::G3D, "Truncating vertex count from %d to %d", vertexCount, vertexCountLimit);
373
vertexCount = vertexCountLimit;
374
}
375
}
376
377
// At this point, rect and line primitives are still preserved as such. So, it's the best time to do software depth raster.
378
// We could piggyback on the viewport transform below, but it gets complicated since it's different per-backend. Which we really
379
// should clean up one day...
380
if (useDepthRaster_) {
381
DepthRasterPredecoded(prim, decoded_, numDecodedVerts_, swDec, vertexCount);
382
}
383
384
SoftwareTransform swTransform(params);
385
386
const Lin::Vec3 trans(gstate_c.vpXOffset, gstate_c.vpYOffset, gstate_c.vpZOffset);
387
const Lin::Vec3 scale(gstate_c.vpWidthScale, gstate_c.vpHeightScale, gstate_c.vpDepthScale);
388
const bool invertedY = gstate_c.vpHeight * (params.flippedY ? 1.0 : -1.0f) < 0;
389
swTransform.SetProjMatrix(gstate.projMatrix, gstate_c.vpWidth < 0, invertedY, trans, scale);
390
391
swTransform.Transform(prim, swDec->VertexType(), swDec->GetDecVtxFmt(), numDecodedVerts_, &result);
392
// Non-zero depth clears are unusual, but some drivers don't match drawn depth values to cleared values.
393
// Games sometimes expect exact matches (see #12626, for example) for equal comparisons.
394
if (result.action == SW_CLEAR && everUsedEqualDepth_ && gstate.isClearModeDepthMask() && result.depth > 0.0f && result.depth < 1.0f)
395
result.action = SW_NOT_READY;
396
397
if (textureNeedsApply) {
398
gstate_c.pixelMapped = result.pixelMapped;
399
textureCache_->ApplyTexture();
400
gstate_c.pixelMapped = false;
401
}
402
403
// Need to ApplyDrawState after ApplyTexture because depal can launch a render pass and that wrecks the state.
404
ApplyDrawState(prim);
405
406
if (result.action == SW_NOT_READY)
407
swTransform.BuildDrawingParams(prim, vertexCount, swDec->VertexType(), inds, RemainingIndices(inds), numDecodedVerts_, VERTEX_BUFFER_MAX, &result);
408
if (result.setSafeSize)
409
framebufferManager_->SetSafeSize(result.safeWidth, result.safeHeight);
410
411
ApplyDrawStateLate(result.setStencil, result.stencilValue);
412
413
LinkedShader *linked = shaderManager_->ApplyFragmentShader(vsid, vshader, pipelineState_, framebufferManager_->UseBufferedRendering());
414
if (!linked) {
415
// Not much we can do here. Let's skip drawing.
416
goto bail;
417
}
418
419
if (result.action == SW_DRAW_INDEXED) {
420
vertexBufferOffset = (uint32_t)frameData.pushVertex->Push(result.drawBuffer, numDecodedVerts_ * sizeof(TransformedVertex), 4, &vertexBuffer);
421
indexBufferOffset = (uint32_t)frameData.pushIndex->Push(inds, sizeof(uint16_t) * result.drawNumTrans, 2, &indexBuffer);
422
render_->DrawIndexed(
423
softwareInputLayout_, vertexBuffer, vertexBufferOffset, indexBuffer, indexBufferOffset,
424
glprim[prim], result.drawNumTrans, GL_UNSIGNED_SHORT);
425
} else if (result.action == SW_CLEAR) {
426
u32 clearColor = result.color;
427
float clearDepth = result.depth;
428
429
bool colorMask = gstate.isClearModeColorMask();
430
bool alphaMask = gstate.isClearModeAlphaMask();
431
bool depthMask = gstate.isClearModeDepthMask();
432
433
GLbitfield target = 0;
434
// Without this, we will clear RGB when clearing stencil, which breaks games.
435
uint8_t rgbaMask = (colorMask ? 7 : 0) | (alphaMask ? 8 : 0);
436
if (colorMask || alphaMask) target |= GL_COLOR_BUFFER_BIT;
437
if (alphaMask) target |= GL_STENCIL_BUFFER_BIT;
438
if (depthMask) target |= GL_DEPTH_BUFFER_BIT;
439
440
render_->Clear(clearColor, clearDepth, clearColor >> 24, target, rgbaMask, vpAndScissor_.scissorX, vpAndScissor_.scissorY, vpAndScissor_.scissorW, vpAndScissor_.scissorH);
441
442
if (gstate_c.Use(GPU_USE_CLEAR_RAM_HACK) && colorMask && (alphaMask || gstate_c.framebufFormat == GE_FORMAT_565)) {
443
int scissorX1 = gstate.getScissorX1();
444
int scissorY1 = gstate.getScissorY1();
445
int scissorX2 = gstate.getScissorX2() + 1;
446
int scissorY2 = gstate.getScissorY2() + 1;
447
framebufferManager_->ApplyClearToMemory(scissorX1, scissorY1, scissorX2, scissorY2, clearColor);
448
}
449
gstate_c.Dirty(DIRTY_BLEND_STATE); // Make sure the color mask gets re-applied.
450
}
451
}
452
453
bail:
454
ResetAfterDrawInline();
455
framebufferManager_->SetColorUpdated(gstate_c.skipDrawReason);
456
gpuCommon_->NotifyFlush();
457
}
458
459
// TODO: Refactor this to a single USE flag.
460
bool DrawEngineGLES::SupportsHWTessellation() {
461
bool hasTexelFetch = gl_extensions.GLES3 || (!gl_extensions.IsGLES && gl_extensions.VersionGEThan(3, 3, 0)) || gl_extensions.EXT_gpu_shader4;
462
return hasTexelFetch && gstate_c.UseAll(GPU_USE_VERTEX_TEXTURE_FETCH | GPU_USE_TEXTURE_FLOAT | GPU_USE_INSTANCE_RENDERING);
463
}
464
465
bool DrawEngineGLES::UpdateUseHWTessellation(bool enable) const {
466
return enable && SupportsHWTessellation();
467
}
468
469
void TessellationDataTransferGLES::SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Spline::Weight2D &weights) {
470
bool hasColor = (vertType & GE_VTYPE_COL_MASK) != 0;
471
bool hasTexCoord = (vertType & GE_VTYPE_TC_MASK) != 0;
472
473
int size = size_u * size_v;
474
float *pos = new float[size * 4];
475
float *tex = hasTexCoord ? new float[size * 4] : nullptr;
476
float *col = hasColor ? new float[size * 4] : nullptr;
477
int stride = 4;
478
479
CopyControlPoints(pos, tex, col, stride, stride, stride, points, size, vertType);
480
// Removed the 1D texture support, it's unlikely to be relevant for performance.
481
// Control Points
482
if (prevSizeU < size_u || prevSizeV < size_v) {
483
prevSizeU = size_u;
484
prevSizeV = size_v;
485
if (data_tex[0])
486
renderManager_->DeleteTexture(data_tex[0]);
487
data_tex[0] = renderManager_->CreateTexture(GL_TEXTURE_2D, size_u * 3, size_v, 1, 1);
488
renderManager_->TextureImage(data_tex[0], 0, size_u * 3, size_v, 1, Draw::DataFormat::R32G32B32A32_FLOAT, nullptr, GLRAllocType::NONE, false);
489
renderManager_->FinalizeTexture(data_tex[0], 0, false);
490
}
491
renderManager_->BindTexture(TEX_SLOT_SPLINE_POINTS, data_tex[0]);
492
// Position
493
renderManager_->TextureSubImage(TEX_SLOT_SPLINE_POINTS, data_tex[0], 0, 0, 0, size_u, size_v, Draw::DataFormat::R32G32B32A32_FLOAT, (u8 *)pos, GLRAllocType::NEW);
494
// Texcoord
495
if (hasTexCoord)
496
renderManager_->TextureSubImage(TEX_SLOT_SPLINE_POINTS, data_tex[0], 0, size_u, 0, size_u, size_v, Draw::DataFormat::R32G32B32A32_FLOAT, (u8 *)tex, GLRAllocType::NEW);
497
// Color
498
if (hasColor)
499
renderManager_->TextureSubImage(TEX_SLOT_SPLINE_POINTS, data_tex[0], 0, size_u * 2, 0, size_u, size_v, Draw::DataFormat::R32G32B32A32_FLOAT, (u8 *)col, GLRAllocType::NEW);
500
501
// Weight U
502
if (prevSizeWU < weights.size_u) {
503
prevSizeWU = weights.size_u;
504
if (data_tex[1])
505
renderManager_->DeleteTexture(data_tex[1]);
506
data_tex[1] = renderManager_->CreateTexture(GL_TEXTURE_2D, weights.size_u * 2, 1, 1, 1);
507
renderManager_->TextureImage(data_tex[1], 0, weights.size_u * 2, 1, 1, Draw::DataFormat::R32G32B32A32_FLOAT, nullptr, GLRAllocType::NONE, false);
508
renderManager_->FinalizeTexture(data_tex[1], 0, false);
509
}
510
renderManager_->BindTexture(TEX_SLOT_SPLINE_WEIGHTS_U, data_tex[1]);
511
renderManager_->TextureSubImage(TEX_SLOT_SPLINE_WEIGHTS_U, data_tex[1], 0, 0, 0, weights.size_u * 2, 1, Draw::DataFormat::R32G32B32A32_FLOAT, (u8 *)weights.u, GLRAllocType::NONE);
512
513
// Weight V
514
if (prevSizeWV < weights.size_v) {
515
prevSizeWV = weights.size_v;
516
if (data_tex[2])
517
renderManager_->DeleteTexture(data_tex[2]);
518
data_tex[2] = renderManager_->CreateTexture(GL_TEXTURE_2D, weights.size_v * 2, 1, 1, 1);
519
renderManager_->TextureImage(data_tex[2], 0, weights.size_v * 2, 1, 1, Draw::DataFormat::R32G32B32A32_FLOAT, nullptr, GLRAllocType::NONE, false);
520
renderManager_->FinalizeTexture(data_tex[2], 0, false);
521
}
522
renderManager_->BindTexture(TEX_SLOT_SPLINE_WEIGHTS_V, data_tex[2]);
523
renderManager_->TextureSubImage(TEX_SLOT_SPLINE_WEIGHTS_V, data_tex[2], 0, 0, 0, weights.size_v * 2, 1, Draw::DataFormat::R32G32B32A32_FLOAT, (u8 *)weights.v, GLRAllocType::NONE);
524
}
525
526
void TessellationDataTransferGLES::EndFrame() {
527
for (int i = 0; i < 3; i++) {
528
if (data_tex[i]) {
529
renderManager_->DeleteTexture(data_tex[i]);
530
data_tex[i] = nullptr;
531
}
532
}
533
prevSizeU = prevSizeV = prevSizeWU = prevSizeWV = 0;
534
}
535
536