~ppsspp/ppsspp/ppsspp-1.1.1

« back to all changes in this revision

Viewing changes to GPU/GLES/StateMapping.cpp

  • Committer: Sérgio Benjamim
  • Date: 2015-10-17 01:37:55 UTC
  • Revision ID: sergio_br2@yahoo.com.br-20151017013755-avrlz2pt37kwt43x
PPSSPP 1.1.1 source.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
19
// Alpha/stencil is a convoluted mess. Some good comments are here:
 
20
// https://github.com/hrydgard/ppsspp/issues/3768
 
21
 
 
22
 
 
23
#include "StateMapping.h"
 
24
#include "profiler/profiler.h"
 
25
 
 
26
#include "GPU/Math3D.h"
 
27
#include "GPU/GPUState.h"
 
28
#include "GPU/ge_constants.h"
 
29
#include "Core/System.h"
 
30
#include "Core/Config.h"
 
31
#include "Core/Reporting.h"
 
32
#include "GPU/GLES/GLES_GPU.h"
 
33
#include "GPU/GLES/GLStateCache.h"
 
34
#include "GPU/GLES/ShaderManager.h"
 
35
#include "GPU/GLES/TextureCache.h"
 
36
#include "GPU/GLES/Framebuffer.h"
 
37
#include "GPU/GLES/FragmentShaderGenerator.h"
 
38
 
 
39
static const GLushort aLookup[11] = {
 
40
        GL_DST_COLOR,
 
41
        GL_ONE_MINUS_DST_COLOR,
 
42
        GL_SRC_ALPHA,
 
43
        GL_ONE_MINUS_SRC_ALPHA,
 
44
        GL_DST_ALPHA,
 
45
        GL_ONE_MINUS_DST_ALPHA,
 
46
        GL_SRC_ALPHA,                   // GE_SRCBLEND_DOUBLESRCALPHA
 
47
        GL_ONE_MINUS_SRC_ALPHA,         // GE_SRCBLEND_DOUBLEINVSRCALPHA
 
48
        GL_DST_ALPHA,                   // GE_SRCBLEND_DOUBLEDSTALPHA
 
49
        GL_ONE_MINUS_DST_ALPHA,         // GE_SRCBLEND_DOUBLEINVDSTALPHA
 
50
        GL_CONSTANT_COLOR,              // FIXA
 
51
};
 
52
 
 
53
static const GLushort bLookup[11] = {
 
54
        GL_SRC_COLOR,
 
55
        GL_ONE_MINUS_SRC_COLOR,
 
56
        GL_SRC_ALPHA,
 
57
        GL_ONE_MINUS_SRC_ALPHA,
 
58
        GL_DST_ALPHA,
 
59
        GL_ONE_MINUS_DST_ALPHA,
 
60
        GL_SRC_ALPHA,                   // GE_DSTBLEND_DOUBLESRCALPHA
 
61
        GL_ONE_MINUS_SRC_ALPHA,         // GE_DSTBLEND_DOUBLEINVSRCALPHA
 
62
        GL_DST_ALPHA,                   // GE_DSTBLEND_DOUBLEDSTALPHA
 
63
        GL_ONE_MINUS_DST_ALPHA,         // GE_DSTBLEND_DOUBLEINVDSTALPHA
 
64
        GL_CONSTANT_COLOR,              // FIXB
 
65
};
 
66
 
 
67
static const GLushort eqLookupNoMinMax[] = {
 
68
        GL_FUNC_ADD,
 
69
        GL_FUNC_SUBTRACT,
 
70
        GL_FUNC_REVERSE_SUBTRACT,
 
71
        GL_FUNC_ADD,                    // GE_BLENDMODE_MIN
 
72
        GL_FUNC_ADD,                    // GE_BLENDMODE_MAX
 
73
        GL_FUNC_ADD,                    // GE_BLENDMODE_ABSDIFF
 
74
};
 
75
 
 
76
static const GLushort eqLookup[] = {
 
77
        GL_FUNC_ADD,
 
78
        GL_FUNC_SUBTRACT,
 
79
        GL_FUNC_REVERSE_SUBTRACT,
 
80
#ifdef USING_GLES2
 
81
        GL_MIN_EXT,                     // GE_BLENDMODE_MIN
 
82
        GL_MAX_EXT,                     // GE_BLENDMODE_MAX
 
83
        GL_MAX_EXT,                     // GE_BLENDMODE_ABSDIFF
 
84
#else
 
85
        GL_MIN,                         // GE_BLENDMODE_MIN
 
86
        GL_MAX,                         // GE_BLENDMODE_MAX
 
87
        GL_MAX,                         // GE_BLENDMODE_ABSDIFF
 
88
#endif
 
89
};
 
90
 
 
91
static const GLushort cullingMode[] = {
 
92
        GL_BACK,
 
93
        GL_FRONT,
 
94
};
 
95
 
 
96
static const GLushort ztests[] = {
 
97
        GL_NEVER, GL_ALWAYS, GL_EQUAL, GL_NOTEQUAL, 
 
98
        GL_LESS, GL_LEQUAL, GL_GREATER, GL_GEQUAL,
 
99
};
 
100
 
 
101
static const GLushort stencilOps[] = {
 
102
        GL_KEEP,
 
103
        GL_ZERO,
 
104
        GL_REPLACE,
 
105
        GL_INVERT,
 
106
        GL_INCR,
 
107
        GL_DECR,
 
108
        GL_KEEP, // reserved
 
109
        GL_KEEP, // reserved
 
110
};
 
111
 
 
112
#if !defined(USING_GLES2)
 
113
static const GLushort logicOps[] = {
 
114
        GL_CLEAR,
 
115
        GL_AND,
 
116
        GL_AND_REVERSE,
 
117
        GL_COPY,
 
118
        GL_AND_INVERTED,
 
119
        GL_NOOP,
 
120
        GL_XOR,
 
121
        GL_OR,
 
122
        GL_NOR,
 
123
        GL_EQUIV,
 
124
        GL_INVERT,
 
125
        GL_OR_REVERSE,
 
126
        GL_COPY_INVERTED,
 
127
        GL_OR_INVERTED,
 
128
        GL_NAND,
 
129
        GL_SET,
 
130
};
 
131
#endif
 
132
 
 
133
static GLenum toDualSource(GLenum blendfunc) {
 
134
        switch (blendfunc) {
 
135
#if !defined(USING_GLES2)   // TODO: Remove when we have better headers
 
136
        case GL_SRC_ALPHA:
 
137
                return GL_SRC1_ALPHA;
 
138
        case GL_ONE_MINUS_SRC_ALPHA:
 
139
                return GL_ONE_MINUS_SRC1_ALPHA;
 
140
#endif
 
141
        default:
 
142
                return blendfunc;
 
143
        }
 
144
}
 
145
 
 
146
static GLenum blendColor2Func(u32 fix, bool &approx) {
 
147
        if (fix == 0xFFFFFF)
 
148
                return GL_ONE;
 
149
        if (fix == 0)
 
150
                return GL_ZERO;
 
151
 
 
152
        // Otherwise, it's approximate if we pick ONE/ZERO.
 
153
        approx = true;
 
154
 
 
155
        const Vec3f fix3 = Vec3f::FromRGB(fix);
 
156
        if (fix3.x >= 0.99 && fix3.y >= 0.99 && fix3.z >= 0.99)
 
157
                return GL_ONE;
 
158
        else if (fix3.x <= 0.01 && fix3.y <= 0.01 && fix3.z <= 0.01)
 
159
                return GL_ZERO;
 
160
        return GL_INVALID_ENUM;
 
161
}
 
162
 
 
163
static inline bool blendColorSimilar(const Vec3f &a, const Vec3f &b, float margin = 0.1f) {
 
164
        const Vec3f diff = a - b;
 
165
        if (fabsf(diff.x) <= margin && fabsf(diff.y) <= margin && fabsf(diff.z) <= margin)
 
166
                return true;
 
167
        return false;
 
168
}
 
169
 
 
170
bool TransformDrawEngine::ApplyShaderBlending() {
 
171
        if (gstate_c.featureFlags & GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH) {
 
172
                return true;
 
173
        }
 
174
 
 
175
        static const int MAX_REASONABLE_BLITS_PER_FRAME = 24;
 
176
 
 
177
        static int lastFrameBlit = -1;
 
178
        static int blitsThisFrame = 0;
 
179
        if (lastFrameBlit != gpuStats.numFlips) {
 
180
                if (blitsThisFrame > MAX_REASONABLE_BLITS_PER_FRAME) {
 
181
                        WARN_LOG_REPORT_ONCE(blendingBlit, G3D, "Lots of blits needed for obscure blending: %d per frame, blend %d/%d/%d", blitsThisFrame, gstate.getBlendFuncA(), gstate.getBlendFuncB(), gstate.getBlendEq());
 
182
                }
 
183
                blitsThisFrame = 0;
 
184
                lastFrameBlit = gpuStats.numFlips;
 
185
        }
 
186
        ++blitsThisFrame;
 
187
        if (blitsThisFrame > MAX_REASONABLE_BLITS_PER_FRAME * 2) {
 
188
                WARN_LOG_ONCE(blendingBlit2, G3D, "Skipping additional blits needed for obscure blending: %d per frame, blend %d/%d/%d", blitsThisFrame, gstate.getBlendFuncA(), gstate.getBlendFuncB(), gstate.getBlendEq());
 
189
                ResetShaderBlending();
 
190
                return false;
 
191
        }
 
192
 
 
193
        fboTexNeedBind_ = true;
 
194
 
 
195
        shaderManager_->DirtyUniform(DIRTY_SHADERBLEND);
 
196
        return true;
 
197
}
 
198
 
 
199
inline void TransformDrawEngine::ResetShaderBlending() {
 
200
        // Wait - what does this have to do with FBOs?
 
201
        if (fboTexBound_) {
 
202
                glActiveTexture(GL_TEXTURE1);
 
203
                glBindTexture(GL_TEXTURE_2D, 0);
 
204
                glActiveTexture(GL_TEXTURE0);
 
205
                fboTexBound_ = false;
 
206
        }
 
207
}
 
208
 
 
209
// Try to simulate some common logic ops.
 
210
void TransformDrawEngine::ApplyStencilReplaceAndLogicOp(ReplaceAlphaType replaceAlphaWithStencil) {
 
211
        StencilValueType stencilType = STENCIL_VALUE_KEEP;
 
212
        if (replaceAlphaWithStencil == REPLACE_ALPHA_YES) {
 
213
                stencilType = ReplaceAlphaWithStencilType();
 
214
        }
 
215
 
 
216
        // Normally, we would add src + 0, but the logic op may have us do differently.
 
217
        GLenum srcBlend = GL_ONE;
 
218
        GLenum dstBlend = GL_ZERO;
 
219
        GLenum blendOp = GL_FUNC_ADD;
 
220
 
 
221
        if (!gstate_c.Supports(GPU_SUPPORTS_LOGIC_OP)) {
 
222
                if (gstate.isLogicOpEnabled()) {
 
223
                        switch (gstate.getLogicOp())
 
224
                        {
 
225
                        case GE_LOGIC_CLEAR:
 
226
                                srcBlend = GL_ZERO;
 
227
                                break;
 
228
                        case GE_LOGIC_AND:
 
229
                        case GE_LOGIC_AND_REVERSE:
 
230
                                WARN_LOG_REPORT_ONCE(d3dLogicOpAnd, G3D, "Unsupported AND logic op: %x", gstate.getLogicOp());
 
231
                                break;
 
232
                        case GE_LOGIC_COPY:
 
233
                                // This is the same as off.
 
234
                                break;
 
235
                        case GE_LOGIC_COPY_INVERTED:
 
236
                                // Handled in the shader.
 
237
                                break;
 
238
                        case GE_LOGIC_AND_INVERTED:
 
239
                        case GE_LOGIC_NOR:
 
240
                        case GE_LOGIC_NAND:
 
241
                        case GE_LOGIC_EQUIV:
 
242
                                // Handled in the shader.
 
243
                                WARN_LOG_REPORT_ONCE(d3dLogicOpAndInverted, G3D, "Attempted invert for logic op: %x", gstate.getLogicOp());
 
244
                                break;
 
245
                        case GE_LOGIC_INVERTED:
 
246
                                srcBlend = GL_ONE;
 
247
                                dstBlend = GL_ONE;
 
248
                                blendOp = GL_FUNC_SUBTRACT;
 
249
                                WARN_LOG_REPORT_ONCE(d3dLogicOpInverted, G3D, "Attempted inverse for logic op: %x", gstate.getLogicOp());
 
250
                                break;
 
251
                        case GE_LOGIC_NOOP:
 
252
                                srcBlend = GL_ZERO;
 
253
                                dstBlend = GL_ONE;
 
254
                                break;
 
255
                        case GE_LOGIC_XOR:
 
256
                                WARN_LOG_REPORT_ONCE(d3dLogicOpOrXor, G3D, "Unsupported XOR logic op: %x", gstate.getLogicOp());
 
257
                                break;
 
258
                        case GE_LOGIC_OR:
 
259
                        case GE_LOGIC_OR_INVERTED:
 
260
                                // Inverted in shader.
 
261
                                dstBlend = GL_ONE;
 
262
                                WARN_LOG_REPORT_ONCE(d3dLogicOpOr, G3D, "Attempted or for logic op: %x", gstate.getLogicOp());
 
263
                                break;
 
264
                        case GE_LOGIC_OR_REVERSE:
 
265
                                WARN_LOG_REPORT_ONCE(d3dLogicOpOrReverse, G3D, "Unsupported OR REVERSE logic op: %x", gstate.getLogicOp());
 
266
                                break;
 
267
                        case GE_LOGIC_SET:
 
268
                                dstBlend = GL_ONE;
 
269
                                WARN_LOG_REPORT_ONCE(d3dLogicOpSet, G3D, "Attempted set for logic op: %x", gstate.getLogicOp());
 
270
                                break;
 
271
                        }
 
272
                }
 
273
        }
 
274
 
 
275
        // We're not blending, but we may still want to blend for stencil.
 
276
        // This is only useful for INCR/DECR/INVERT.  Others can write directly.
 
277
        switch (stencilType) {
 
278
        case STENCIL_VALUE_INCR_4:
 
279
        case STENCIL_VALUE_INCR_8:
 
280
                // We'll add the incremented value output by the shader.
 
281
                glstate.blendFuncSeparate.set(srcBlend, dstBlend, GL_ONE, GL_ONE);
 
282
                glstate.blendEquationSeparate.set(blendOp, GL_FUNC_ADD);
 
283
                glstate.blend.enable();
 
284
                break;
 
285
 
 
286
        case STENCIL_VALUE_DECR_4:
 
287
        case STENCIL_VALUE_DECR_8:
 
288
                // We'll subtract the incremented value output by the shader.
 
289
                glstate.blendFuncSeparate.set(srcBlend, dstBlend, GL_ONE, GL_ONE);
 
290
                glstate.blendEquationSeparate.set(blendOp, GL_FUNC_SUBTRACT);
 
291
                glstate.blend.enable();
 
292
                break;
 
293
 
 
294
        case STENCIL_VALUE_INVERT:
 
295
                // The shader will output one, and reverse subtracting will essentially invert.
 
296
                glstate.blendFuncSeparate.set(srcBlend, dstBlend, GL_ONE, GL_ONE);
 
297
                glstate.blendEquationSeparate.set(blendOp, GL_FUNC_REVERSE_SUBTRACT);
 
298
                glstate.blend.enable();
 
299
                break;
 
300
 
 
301
        default:
 
302
                if (srcBlend == GL_ONE && dstBlend == GL_ZERO && blendOp == GL_FUNC_ADD) {
 
303
                        glstate.blend.disable();
 
304
                } else {
 
305
                        glstate.blendFuncSeparate.set(srcBlend, dstBlend, GL_ONE, GL_ZERO);
 
306
                        glstate.blendEquationSeparate.set(blendOp, GL_FUNC_ADD);
 
307
                        glstate.blend.enable();
 
308
                }
 
309
                break;
 
310
        }
 
311
}
 
312
 
 
313
// Called even if AlphaBlendEnable == false - it also deals with stencil-related blend state.
 
314
 
 
315
void TransformDrawEngine::ApplyBlendState() {
 
316
        // Blending is a bit complex to emulate.  This is due to several reasons:
 
317
        //
 
318
        //  * Doubled blend modes (src, dst, inversed) aren't supported in OpenGL.
 
319
        //    If possible, we double the src color or src alpha in the shader to account for these.
 
320
        //    These may clip incorrectly, so we avoid unfortunately.
 
321
        //  * OpenGL only has one arbitrary fixed color.  We premultiply the other in the shader.
 
322
        //  * The written output alpha should actually be the stencil value.  Alpha is not written.
 
323
        //
 
324
        // If we can't apply blending, we make a copy of the framebuffer and do it manually.
 
325
        gstate_c.allowShaderBlend = !g_Config.bDisableSlowFramebufEffects;
 
326
 
 
327
        ReplaceBlendType replaceBlend = ReplaceBlendWithShader(gstate_c.allowShaderBlend);
 
328
        ReplaceAlphaType replaceAlphaWithStencil = ReplaceAlphaWithStencil(replaceBlend);
 
329
        bool usePreSrc = false;
 
330
 
 
331
        switch (replaceBlend) {
 
332
        case REPLACE_BLEND_NO:
 
333
                ResetShaderBlending();
 
334
                // We may still want to do something about stencil -> alpha.
 
335
                ApplyStencilReplaceAndLogicOp(replaceAlphaWithStencil);
 
336
                return;
 
337
 
 
338
        case REPLACE_BLEND_COPY_FBO:
 
339
                if (ApplyShaderBlending()) {
 
340
                        // We may still want to do something about stencil -> alpha.
 
341
                        ApplyStencilReplaceAndLogicOp(replaceAlphaWithStencil);
 
342
                        return;
 
343
                }
 
344
                // Until next time, force it off.
 
345
                gstate_c.allowShaderBlend = false;
 
346
                break;
 
347
 
 
348
        case REPLACE_BLEND_PRE_SRC:
 
349
        case REPLACE_BLEND_PRE_SRC_2X_ALPHA:
 
350
                usePreSrc = true;
 
351
                break;
 
352
 
 
353
        case REPLACE_BLEND_STANDARD:
 
354
        case REPLACE_BLEND_2X_ALPHA:
 
355
        case REPLACE_BLEND_2X_SRC:
 
356
                break;
 
357
        }
 
358
 
 
359
        glstate.blend.enable();
 
360
        ResetShaderBlending();
 
361
 
 
362
        const GEBlendMode blendFuncEq = gstate.getBlendEq();
 
363
        int blendFuncA = gstate.getBlendFuncA();
 
364
        int blendFuncB = gstate.getBlendFuncB();
 
365
        const u32 fixA = gstate.getFixA();
 
366
        const u32 fixB = gstate.getFixB();
 
367
 
 
368
        if (blendFuncA > GE_SRCBLEND_FIXA)
 
369
                blendFuncA = GE_SRCBLEND_FIXA;
 
370
        if (blendFuncB > GE_DSTBLEND_FIXB)
 
371
                blendFuncB = GE_DSTBLEND_FIXB;
 
372
 
 
373
        float constantAlpha = 1.0f;
 
374
        GLenum constantAlphaGL = GL_ONE;
 
375
        if (gstate.isStencilTestEnabled() && replaceAlphaWithStencil == REPLACE_ALPHA_NO) {
 
376
                switch (ReplaceAlphaWithStencilType()) {
 
377
                case STENCIL_VALUE_UNIFORM:
 
378
                        constantAlpha = (float) gstate.getStencilTestRef() * (1.0f / 255.0f);
 
379
                        break;
 
380
 
 
381
                case STENCIL_VALUE_INCR_4:
 
382
                case STENCIL_VALUE_DECR_4:
 
383
                        constantAlpha = 1.0f / 15.0f;
 
384
                        break;
 
385
 
 
386
                case STENCIL_VALUE_INCR_8:
 
387
                case STENCIL_VALUE_DECR_8:
 
388
                        constantAlpha = 1.0f / 255.0f;
 
389
                        break;
 
390
 
 
391
                default:
 
392
                        break;
 
393
                }
 
394
 
 
395
                // Otherwise it will stay GL_ONE.
 
396
                if (constantAlpha <= 0.0f) {
 
397
                        constantAlphaGL = GL_ZERO;
 
398
                } else if (constantAlpha < 1.0f) {
 
399
                        constantAlphaGL = GL_CONSTANT_ALPHA;
 
400
                }
 
401
        }
 
402
 
 
403
        // Shortcut by using GL_ONE where possible, no need to set blendcolor
 
404
        bool approxFuncA = false;
 
405
        GLuint glBlendFuncA = blendFuncA == GE_SRCBLEND_FIXA ? blendColor2Func(fixA, approxFuncA) : aLookup[blendFuncA];
 
406
        bool approxFuncB = false;
 
407
        GLuint glBlendFuncB = blendFuncB == GE_DSTBLEND_FIXB ? blendColor2Func(fixB, approxFuncB) : bLookup[blendFuncB];
 
408
 
 
409
        if (usePreSrc) {
 
410
                glBlendFuncA = GL_ONE;
 
411
                // Need to pull in the fixed color.
 
412
                if (blendFuncA == GE_SRCBLEND_FIXA) {
 
413
                        shaderManager_->DirtyUniform(DIRTY_SHADERBLEND);
 
414
                }
 
415
        }
 
416
 
 
417
        if (replaceAlphaWithStencil == REPLACE_ALPHA_DUALSOURCE && gstate_c.Supports(GPU_SUPPORTS_DUALSOURCE_BLEND)) {
 
418
                glBlendFuncA = toDualSource(glBlendFuncA);
 
419
                glBlendFuncB = toDualSource(glBlendFuncB);
 
420
        }
 
421
 
 
422
        auto setBlendColorv = [&](const Vec3f &c) {
 
423
                const float blendColor[4] = {c.x, c.y, c.z, constantAlpha};
 
424
                glstate.blendColor.set(blendColor);
 
425
        };
 
426
        auto defaultBlendColor = [&]() {
 
427
                if (constantAlphaGL == GL_CONSTANT_ALPHA) {
 
428
                        const float blendColor[4] = {1.0f, 1.0f, 1.0f, constantAlpha};
 
429
                        glstate.blendColor.set(blendColor);
 
430
                }
 
431
        };
 
432
 
 
433
        if (blendFuncA == GE_SRCBLEND_FIXA || blendFuncB == GE_DSTBLEND_FIXB) {
 
434
                const Vec3f fixAVec = Vec3f::FromRGB(fixA);
 
435
                const Vec3f fixBVec = Vec3f::FromRGB(fixB);
 
436
                if (glBlendFuncA == GL_INVALID_ENUM && glBlendFuncB != GL_INVALID_ENUM) {
 
437
                        // Can use blendcolor trivially.
 
438
                        setBlendColorv(fixAVec);
 
439
                        glBlendFuncA = GL_CONSTANT_COLOR;
 
440
                } else if (glBlendFuncA != GL_INVALID_ENUM && glBlendFuncB == GL_INVALID_ENUM) {
 
441
                        // Can use blendcolor trivially.
 
442
                        setBlendColorv(fixBVec);
 
443
                        glBlendFuncB = GL_CONSTANT_COLOR;
 
444
                } else if (glBlendFuncA == GL_INVALID_ENUM && glBlendFuncB == GL_INVALID_ENUM) {
 
445
                        if (blendColorSimilar(fixAVec, Vec3f::AssignToAll(1.0f) - fixBVec)) {
 
446
                                glBlendFuncA = GL_CONSTANT_COLOR;
 
447
                                glBlendFuncB = GL_ONE_MINUS_CONSTANT_COLOR;
 
448
                                setBlendColorv(fixAVec);
 
449
                        } else if (blendColorSimilar(fixAVec, fixBVec)) {
 
450
                                glBlendFuncA = GL_CONSTANT_COLOR;
 
451
                                glBlendFuncB = GL_CONSTANT_COLOR;
 
452
                                setBlendColorv(fixAVec);
 
453
                        } else {
 
454
                                DEBUG_LOG(G3D, "ERROR INVALID blendcolorstate: FixA=%06x FixB=%06x FuncA=%i FuncB=%i", fixA, fixB, blendFuncA, blendFuncB);
 
455
                                // Let's approximate, at least.  Close is better than totally off.
 
456
                                const bool nearZeroA = blendColorSimilar(fixAVec, Vec3f::AssignToAll(0.0f), 0.25f);
 
457
                                const bool nearZeroB = blendColorSimilar(fixBVec, Vec3f::AssignToAll(0.0f), 0.25f);
 
458
                                if (nearZeroA || blendColorSimilar(fixAVec, Vec3f::AssignToAll(1.0f), 0.25f)) {
 
459
                                        glBlendFuncA = nearZeroA ? GL_ZERO : GL_ONE;
 
460
                                        glBlendFuncB = GL_CONSTANT_COLOR;
 
461
                                        setBlendColorv(fixBVec);
 
462
                                } else {
 
463
                                        // We need to pick something.  Let's go with A as the fixed color.
 
464
                                        glBlendFuncA = GL_CONSTANT_COLOR;
 
465
                                        glBlendFuncB = nearZeroB ? GL_ZERO : GL_ONE;
 
466
                                        setBlendColorv(fixAVec);
 
467
                                }
 
468
                        }
 
469
                } else {
 
470
                        // We optimized both, but that's probably not necessary, so let's pick one to be constant.
 
471
                        if (blendFuncA == GE_SRCBLEND_FIXA && !usePreSrc && approxFuncA) {
 
472
                                glBlendFuncA = GL_CONSTANT_COLOR;
 
473
                                setBlendColorv(fixAVec);
 
474
                        } else if (approxFuncB) {
 
475
                                glBlendFuncB = GL_CONSTANT_COLOR;
 
476
                                setBlendColorv(fixBVec);
 
477
                        } else {
 
478
                                defaultBlendColor();
 
479
                        }
 
480
                }
 
481
        } else {
 
482
                defaultBlendColor();
 
483
        }
 
484
 
 
485
        // Some Android devices (especially Mali, it seems) composite badly if there's alpha in the backbuffer.
 
486
        // So in non-buffered rendering, we will simply consider the dest alpha to be zero in blending equations.
 
487
#ifdef ANDROID
 
488
        if (g_Config.iRenderingMode == FB_NON_BUFFERED_MODE) {
 
489
                if (glBlendFuncA == GL_DST_ALPHA) glBlendFuncA = GL_ZERO;
 
490
                if (glBlendFuncB == GL_DST_ALPHA) glBlendFuncB = GL_ZERO;
 
491
                if (glBlendFuncA == GL_ONE_MINUS_DST_ALPHA) glBlendFuncA = GL_ONE;
 
492
                if (glBlendFuncB == GL_ONE_MINUS_DST_ALPHA) glBlendFuncB = GL_ONE;
 
493
        }
 
494
#endif
 
495
 
 
496
        // At this point, through all paths above, glBlendFuncA and glBlendFuncB will be set right somehow.
 
497
 
 
498
        // The stencil-to-alpha in fragment shader doesn't apply here (blending is enabled), and we shouldn't
 
499
        // do any blending in the alpha channel as that doesn't seem to happen on PSP.  So, we attempt to
 
500
        // apply the stencil to the alpha, since that's what should be stored.
 
501
        GLenum alphaEq = GL_FUNC_ADD;
 
502
        if (replaceAlphaWithStencil != REPLACE_ALPHA_NO) {
 
503
                // Let the fragment shader take care of it.
 
504
                switch (ReplaceAlphaWithStencilType()) {
 
505
                case STENCIL_VALUE_INCR_4:
 
506
                case STENCIL_VALUE_INCR_8:
 
507
                        // We'll add the increment value.
 
508
                        glstate.blendFuncSeparate.set(glBlendFuncA, glBlendFuncB, GL_ONE, GL_ONE);
 
509
                        break;
 
510
 
 
511
                case STENCIL_VALUE_DECR_4:
 
512
                case STENCIL_VALUE_DECR_8:
 
513
                        // Like add with a small value, but subtracting.
 
514
                        glstate.blendFuncSeparate.set(glBlendFuncA, glBlendFuncB, GL_ONE, GL_ONE);
 
515
                        alphaEq = GL_FUNC_SUBTRACT;
 
516
                        break;
 
517
 
 
518
                case STENCIL_VALUE_INVERT:
 
519
                        // This will subtract by one, effectively inverting the bits.
 
520
                        glstate.blendFuncSeparate.set(glBlendFuncA, glBlendFuncB, GL_ONE, GL_ONE);
 
521
                        alphaEq = GL_FUNC_REVERSE_SUBTRACT;
 
522
                        break;
 
523
 
 
524
                default:
 
525
                        glstate.blendFuncSeparate.set(glBlendFuncA, glBlendFuncB, GL_ONE, GL_ZERO);
 
526
                        break;
 
527
                }
 
528
        } else if (gstate.isStencilTestEnabled()) {
 
529
                switch (ReplaceAlphaWithStencilType()) {
 
530
                case STENCIL_VALUE_KEEP:
 
531
                        glstate.blendFuncSeparate.set(glBlendFuncA, glBlendFuncB, GL_ZERO, GL_ONE);
 
532
                        break;
 
533
                case STENCIL_VALUE_ONE:
 
534
                        // This won't give one but it's our best shot...
 
535
                        glstate.blendFuncSeparate.set(glBlendFuncA, glBlendFuncB, GL_ONE, GL_ONE);
 
536
                        break;
 
537
                case STENCIL_VALUE_ZERO:
 
538
                        glstate.blendFuncSeparate.set(glBlendFuncA, glBlendFuncB, GL_ZERO, GL_ZERO);
 
539
                        break;
 
540
                case STENCIL_VALUE_UNIFORM:
 
541
                        // This won't give a correct value (it multiplies) but it may be better than random values.
 
542
                        glstate.blendFuncSeparate.set(glBlendFuncA, glBlendFuncB, constantAlphaGL, GL_ZERO);
 
543
                        break;
 
544
                case STENCIL_VALUE_INCR_4:
 
545
                case STENCIL_VALUE_INCR_8:
 
546
                        // This won't give a correct value always, but it will try to increase at least.
 
547
                        glstate.blendFuncSeparate.set(glBlendFuncA, glBlendFuncB, constantAlphaGL, GL_ONE);
 
548
                        break;
 
549
                case STENCIL_VALUE_DECR_4:
 
550
                case STENCIL_VALUE_DECR_8:
 
551
                        // This won't give a correct value always, but it will try to decrease at least.
 
552
                        glstate.blendFuncSeparate.set(glBlendFuncA, glBlendFuncB, constantAlphaGL, GL_ONE);
 
553
                        alphaEq = GL_FUNC_SUBTRACT;
 
554
                        break;
 
555
                case STENCIL_VALUE_INVERT:
 
556
                        glstate.blendFuncSeparate.set(glBlendFuncA, glBlendFuncB, GL_ONE, GL_ONE);
 
557
                        // If the output alpha is near 1, this will basically invert.  It's our best shot.
 
558
                        alphaEq = GL_FUNC_REVERSE_SUBTRACT;
 
559
                        break;
 
560
                }
 
561
        } else {
 
562
                // Retain the existing value when stencil testing is off.
 
563
                glstate.blendFuncSeparate.set(glBlendFuncA, glBlendFuncB, GL_ZERO, GL_ONE);
 
564
        }
 
565
 
 
566
        if (gstate_c.Supports(GPU_SUPPORTS_BLEND_MINMAX)) {
 
567
                glstate.blendEquationSeparate.set(eqLookup[blendFuncEq], alphaEq);
 
568
        } else {
 
569
                glstate.blendEquationSeparate.set(eqLookupNoMinMax[blendFuncEq], alphaEq);
 
570
        }
 
571
}
 
572
 
 
573
void TransformDrawEngine::ApplyDrawState(int prim) {
 
574
 
 
575
        // TODO: All this setup is soon so expensive that we'll need dirty flags, or simply do it in the command writes where we detect dirty by xoring. Silly to do all this work on every drawcall.
 
576
 
 
577
        if (gstate_c.textureChanged != TEXCHANGE_UNCHANGED && !gstate.isModeClear() && gstate.isTextureMapEnabled()) {
 
578
                textureCache_->SetTexture();
 
579
                gstate_c.textureChanged = TEXCHANGE_UNCHANGED;
 
580
                if (gstate_c.needShaderTexClamp) {
 
581
                        // We will rarely need to set this, so let's do it every time on use rather than in runloop.
 
582
                        // Most of the time non-framebuffer textures will be used which can be clamped themselves.
 
583
                        shaderManager_->DirtyUniform(DIRTY_TEXCLAMP);
 
584
                }
 
585
        }
 
586
 
 
587
        // Start profiling here to skip SetTexture which is already accounted for
 
588
        PROFILE_THIS_SCOPE("applydrawstate");
 
589
 
 
590
        // Set blend - unless we need to do it in the shader.
 
591
        ApplyBlendState();
 
592
 
 
593
        bool alwaysDepthWrite = g_Config.bAlwaysDepthWrite;
 
594
        bool enableStencilTest = !g_Config.bDisableStencilTest;
 
595
 
 
596
        // Dither
 
597
        if (gstate.isDitherEnabled()) {
 
598
                glstate.dither.enable();
 
599
                glstate.dither.set(GL_TRUE);
 
600
        } else
 
601
                glstate.dither.disable();
 
602
 
 
603
        if (gstate.isModeClear()) {
 
604
#ifndef USING_GLES2
 
605
                if (gstate_c.Supports(GPU_SUPPORTS_LOGIC_OP)) {
 
606
                        // Logic Ops
 
607
                        glstate.colorLogicOp.disable();
 
608
                }
 
609
#endif
 
610
                // Culling
 
611
                glstate.cullFace.disable();
 
612
 
 
613
                // Depth Test
 
614
                glstate.depthTest.enable();
 
615
                glstate.depthFunc.set(GL_ALWAYS);
 
616
                glstate.depthWrite.set(gstate.isClearModeDepthMask() || alwaysDepthWrite ? GL_TRUE : GL_FALSE);
 
617
                if (gstate.isClearModeDepthMask() || alwaysDepthWrite) {
 
618
                        framebufferManager_->SetDepthUpdated();
 
619
                }
 
620
 
 
621
                // Color Test
 
622
                bool colorMask = gstate.isClearModeColorMask();
 
623
                bool alphaMask = gstate.isClearModeAlphaMask();
 
624
                glstate.colorMask.set(colorMask, colorMask, colorMask, alphaMask);
 
625
 
 
626
                // Stencil Test
 
627
                if (alphaMask && enableStencilTest) {
 
628
                        glstate.stencilTest.enable();
 
629
                        glstate.stencilOp.set(GL_REPLACE, GL_REPLACE, GL_REPLACE);
 
630
                        // TODO: In clear mode, the stencil value is set to the alpha value of the vertex.
 
631
                        // A normal clear will be 2 points, the second point has the color.
 
632
                        // We should set "ref" to that value instead of 0.
 
633
                        // In case of clear rectangles, we set it again once we know what the color is.
 
634
                        glstate.stencilFunc.set(GL_ALWAYS, 255, 0xFF);
 
635
                        glstate.stencilMask.set(0xFF);
 
636
                } else {
 
637
                        glstate.stencilTest.disable();
 
638
                }
 
639
        } else {
 
640
#ifndef USING_GLES2
 
641
                if (gstate_c.Supports(GPU_SUPPORTS_LOGIC_OP)) {
 
642
                        // TODO: Make this dynamic
 
643
                        // Logic Ops
 
644
                        if (gstate.isLogicOpEnabled() && gstate.getLogicOp() != GE_LOGIC_COPY) {
 
645
                                glstate.colorLogicOp.enable();
 
646
                                glstate.logicOp.set(logicOps[gstate.getLogicOp()]);
 
647
                        } else {
 
648
                                glstate.colorLogicOp.disable();
 
649
                        }
 
650
                }
 
651
#endif
 
652
                // Set cull
 
653
                bool cullEnabled = !gstate.isModeThrough() && prim != GE_PRIM_RECTANGLES && gstate.isCullEnabled();
 
654
                if (cullEnabled) {
 
655
                        glstate.cullFace.enable();
 
656
                        glstate.cullFaceMode.set(cullingMode[gstate.getCullMode()]);
 
657
                } else {
 
658
                        glstate.cullFace.disable();
 
659
                }
 
660
 
 
661
                // Depth Test
 
662
                if (gstate.isDepthTestEnabled()) {
 
663
                        glstate.depthTest.enable();
 
664
                        glstate.depthFunc.set(ztests[gstate.getDepthTestFunction()]);
 
665
                        glstate.depthWrite.set(gstate.isDepthWriteEnabled() || alwaysDepthWrite ? GL_TRUE : GL_FALSE);
 
666
                        if (gstate.isDepthWriteEnabled() || alwaysDepthWrite) {
 
667
                                framebufferManager_->SetDepthUpdated();
 
668
                        }
 
669
                } else {
 
670
                        glstate.depthTest.disable();
 
671
                }
 
672
 
 
673
                // PSP color/alpha mask is per bit but we can only support per byte.
 
674
                // But let's do that, at least. And let's try a threshold.
 
675
                bool rmask = (gstate.pmskc & 0xFF) < 128;
 
676
                bool gmask = ((gstate.pmskc >> 8) & 0xFF) < 128;
 
677
                bool bmask = ((gstate.pmskc >> 16) & 0xFF) < 128;
 
678
                bool amask = (gstate.pmska & 0xFF) < 128;
 
679
 
 
680
                u8 abits = (gstate.pmska >> 0) & 0xFF;
 
681
#ifndef MOBILE_DEVICE
 
682
                u8 rbits = (gstate.pmskc >> 0) & 0xFF;
 
683
                u8 gbits = (gstate.pmskc >> 8) & 0xFF;
 
684
                u8 bbits = (gstate.pmskc >> 16) & 0xFF;
 
685
                if ((rbits != 0 && rbits != 0xFF) || (gbits != 0 && gbits != 0xFF) || (bbits != 0 && bbits != 0xFF)) {
 
686
                        WARN_LOG_REPORT_ONCE(rgbmask, G3D, "Unsupported RGB mask: r=%02x g=%02x b=%02x", rbits, gbits, bbits);
 
687
                }
 
688
                if (abits != 0 && abits != 0xFF) {
 
689
                        // The stencil part of the mask is supported.
 
690
                        WARN_LOG_REPORT_ONCE(amask, G3D, "Unsupported alpha/stencil mask: %02x", abits);
 
691
                }
 
692
#endif
 
693
 
 
694
                // Let's not write to alpha if stencil isn't enabled.
 
695
                if (!gstate.isStencilTestEnabled()) {
 
696
                        amask = false;
 
697
                } else {
 
698
                        // If the stencil type is set to KEEP, we shouldn't write to the stencil/alpha channel.
 
699
                        if (ReplaceAlphaWithStencilType() == STENCIL_VALUE_KEEP) {
 
700
                                amask = false;
 
701
                        }
 
702
                }
 
703
 
 
704
                glstate.colorMask.set(rmask, gmask, bmask, amask);
 
705
 
 
706
                // Stencil Test
 
707
                if (gstate.isStencilTestEnabled() && enableStencilTest) {
 
708
                        glstate.stencilTest.enable();
 
709
                        glstate.stencilFunc.set(ztests[gstate.getStencilTestFunction()],
 
710
                                gstate.getStencilTestRef(),
 
711
                                gstate.getStencilTestMask());
 
712
                        glstate.stencilOp.set(stencilOps[gstate.getStencilOpSFail()],  // stencil fail
 
713
                                stencilOps[gstate.getStencilOpZFail()],  // depth fail
 
714
                                stencilOps[gstate.getStencilOpZPass()]); // depth pass
 
715
 
 
716
                        if (gstate.FrameBufFormat() == GE_FORMAT_5551) {
 
717
                                glstate.stencilMask.set(abits <= 0x7f ? 0xff : 0x00);
 
718
                        } else {
 
719
                                glstate.stencilMask.set(~abits);
 
720
                        }
 
721
                } else {
 
722
                        glstate.stencilTest.disable();
 
723
                }
 
724
        }
 
725
 
 
726
        bool throughmode = gstate.isModeThrough();
 
727
 
 
728
        float renderWidthFactor, renderHeightFactor;
 
729
        float renderWidth, renderHeight;
 
730
        float renderX, renderY;
 
731
        bool useBufferedRendering = g_Config.iRenderingMode != FB_NON_BUFFERED_MODE;
 
732
        if (useBufferedRendering) {
 
733
                renderX = 0.0f;
 
734
                renderY = 0.0f;
 
735
                renderWidth = framebufferManager_->GetRenderWidth();
 
736
                renderHeight = framebufferManager_->GetRenderHeight();
 
737
                renderWidthFactor = (float)renderWidth / framebufferManager_->GetTargetBufferWidth();
 
738
                renderHeightFactor = (float)renderHeight / framebufferManager_->GetTargetBufferHeight();
 
739
        } else {
 
740
                float pixelW = PSP_CoreParameter().pixelWidth;
 
741
                float pixelH = PSP_CoreParameter().pixelHeight;
 
742
                CenterRect(&renderX, &renderY, &renderWidth, &renderHeight, 480, 272, pixelW, pixelH, ROTATION_LOCKED_HORIZONTAL);
 
743
                renderWidthFactor = renderWidth / 480.0f;
 
744
                renderHeightFactor = renderHeight / 272.0f;
 
745
        }
 
746
 
 
747
        renderX += gstate_c.curRTOffsetX * renderWidthFactor;
 
748
 
 
749
        // Scissor
 
750
        int scissorX1 = gstate.getScissorX1();
 
751
        int scissorY1 = gstate.getScissorY1();
 
752
        int scissorX2 = gstate.getScissorX2() + 1;
 
753
        int scissorY2 = gstate.getScissorY2() + 1;
 
754
 
 
755
        // This is a bit of a hack as the render buffer isn't always that size
 
756
        if (scissorX1 == 0 && scissorY1 == 0 
 
757
                && scissorX2 >= (int) gstate_c.curRTWidth
 
758
                && scissorY2 >= (int) gstate_c.curRTHeight) {
 
759
                glstate.scissorTest.disable();
 
760
        } else {
 
761
                glstate.scissorTest.enable();
 
762
                glstate.scissorRect.set(
 
763
                        renderX + scissorX1 * renderWidthFactor,
 
764
                        renderY + renderHeight - (scissorY2 * renderHeightFactor),
 
765
                        (scissorX2 - scissorX1) * renderWidthFactor,
 
766
                        (scissorY2 - scissorY1) * renderHeightFactor);
 
767
        }
 
768
 
 
769
        /*
 
770
        int regionX1 = gstate.region1 & 0x3FF;
 
771
        int regionY1 = (gstate.region1 >> 10) & 0x3FF;
 
772
        int regionX2 = (gstate.region2 & 0x3FF) + 1;
 
773
        int regionY2 = ((gstate.region2 >> 10) & 0x3FF) + 1;
 
774
        */
 
775
        int regionX1 = 0;
 
776
        int regionY1 = 0;
 
777
        int regionX2 = gstate_c.curRTWidth;
 
778
        int regionY2 = gstate_c.curRTHeight;
 
779
 
 
780
        float offsetX = gstate.getOffsetX();
 
781
        float offsetY = gstate.getOffsetY();
 
782
 
 
783
        if (throughmode) {
 
784
                // If the buffer is too large, offset the viewport to the top.
 
785
                renderY += renderHeight - framebufferManager_->GetTargetHeight() * renderHeightFactor;
 
786
 
 
787
                // No viewport transform here. Let's experiment with using region.
 
788
                glstate.viewport.set(
 
789
                        renderX + (0 + regionX1) * renderWidthFactor, 
 
790
                        renderY + (0 - regionY1) * renderHeightFactor,
 
791
                        (regionX2 - regionX1) * renderWidthFactor,
 
792
                        (regionY2 - regionY1) * renderHeightFactor);
 
793
                glstate.depthRange.set(0.0f, 1.0f);
 
794
        } else {
 
795
                // These we can turn into a glViewport call, offset by offsetX and offsetY. Math after.
 
796
                float vpXScale = gstate.getViewportXScale();
 
797
                float vpXCenter = gstate.getViewportXCenter();
 
798
                float vpYScale = gstate.getViewportYScale();
 
799
                float vpYCenter = gstate.getViewportYCenter();
 
800
 
 
801
                // The viewport transform appears to go like this:
 
802
                // Xscreen = -offsetX + vpXCenter + vpXScale * Xview
 
803
                // Yscreen = -offsetY + vpYCenter + vpYScale * Yview
 
804
                // Zscreen = vpZCenter + vpZScale * Zview
 
805
 
 
806
                // This means that to get the analogue glViewport we must:
 
807
                float vpX0 = vpXCenter - offsetX - fabsf(vpXScale);
 
808
                float vpY0 = vpYCenter - offsetY + fabsf(vpYScale);   // Need to account for sign of Y
 
809
                gstate_c.vpWidth = vpXScale * 2.0f;
 
810
                gstate_c.vpHeight = -vpYScale * 2.0f;
 
811
 
 
812
                float vpWidth = fabsf(gstate_c.vpWidth);
 
813
                float vpHeight = fabsf(gstate_c.vpHeight);
 
814
 
 
815
                vpX0 *= renderWidthFactor;
 
816
                vpY0 *= renderHeightFactor;
 
817
                vpWidth *= renderWidthFactor;
 
818
                vpHeight *= renderHeightFactor;
 
819
 
 
820
                // Flip vpY0 to match the OpenGL coordinate system.
 
821
                vpY0 = renderHeight - vpY0;
 
822
 
 
823
                // We used to apply the viewport here via glstate, but there are limits which vary by driver.
 
824
                // This may mean some games won't work, or at least won't work at higher render resolutions.
 
825
                // So we apply it in the shader instead.
 
826
                float left = renderX + vpX0;
 
827
                float bottom = renderY + vpY0;
 
828
                float right = left + vpWidth;
 
829
                float top = bottom + vpHeight;
 
830
 
 
831
                float wScale = 1.0f;
 
832
                float xOffset = 0.0f;
 
833
                float hScale = 1.0f;
 
834
                float yOffset = 0.0f;
 
835
 
 
836
                // If we're within the bounds, we want clipping the viewport way.  So leave it be.
 
837
                if (left < 0.0f || right > renderWidth) {
 
838
                        float overageLeft = std::max(-left, 0.0f);
 
839
                        float overageRight = std::max(right - renderWidth, 0.0f);
 
840
                        // Our center drifted by the difference in overages.
 
841
                        float drift = overageRight - overageLeft;
 
842
 
 
843
                        left += overageLeft;
 
844
                        right -= overageRight;
 
845
 
 
846
                        wScale = vpWidth / (right - left);
 
847
                        xOffset = drift / (right - left);
 
848
                }
 
849
 
 
850
                if (bottom < 0.0f || top > renderHeight) {
 
851
                        float overageBottom = std::max(-bottom, 0.0f);
 
852
                        float overageTop = std::max(top - renderHeight, 0.0f);
 
853
                        // Our center drifted by the difference in overages.
 
854
                        float drift = overageTop - overageBottom;
 
855
 
 
856
                        bottom += overageBottom;
 
857
                        top -= overageTop;
 
858
 
 
859
                        hScale = vpHeight / (top - bottom);
 
860
                        yOffset = drift / (top - bottom);
 
861
                }
 
862
 
 
863
                bool scaleChanged = gstate_c.vpWidthScale != wScale || gstate_c.vpHeightScale != hScale;
 
864
                bool offsetChanged = gstate_c.vpXOffset != xOffset || gstate_c.vpYOffset != yOffset;
 
865
                if (scaleChanged || offsetChanged) {
 
866
                        gstate_c.vpWidthScale = wScale;
 
867
                        gstate_c.vpHeightScale = hScale;
 
868
                        gstate_c.vpXOffset = xOffset;
 
869
                        gstate_c.vpYOffset = yOffset;
 
870
                        shaderManager_->DirtyUniform(DIRTY_PROJMATRIX);
 
871
                }
 
872
 
 
873
                glstate.viewport.set(left, bottom, right - left, top - bottom);
 
874
 
 
875
                float zScale = gstate.getViewportZScale();
 
876
                float zCenter = gstate.getViewportZCenter();
 
877
                float depthRangeMin = zCenter - zScale;
 
878
                float depthRangeMax = zCenter + zScale;
 
879
                glstate.depthRange.set(depthRangeMin * (1.0f / 65535.0f), depthRangeMax * (1.0f / 65535.0f));
 
880
 
 
881
#ifndef MOBILE_DEVICE
 
882
                float minz = gstate.getDepthRangeMin() * (1.0f / 65535.0f);
 
883
                float maxz = gstate.getDepthRangeMax() * (1.0f / 65535.0f);
 
884
                if ((minz > depthRangeMin && minz > depthRangeMax) || (maxz < depthRangeMin && maxz < depthRangeMax)) {
 
885
                        WARN_LOG_REPORT_ONCE(minmaxz, G3D, "Unsupported depth range test - depth range: %f-%f, test: %f-%f", depthRangeMin, depthRangeMax, minz, maxz);
 
886
                } else if ((gstate.clipEnable & 1) == 0) {
 
887
                        // TODO: Need to test whether clipEnable should even affect depth or not.
 
888
                        if ((minz < depthRangeMin && minz < depthRangeMax) || (maxz > depthRangeMin && maxz > depthRangeMax)) {
 
889
                                WARN_LOG_REPORT_ONCE(znoclip, G3D, "Unsupported depth range test without clipping - depth range: %f-%f, test: %f-%f", depthRangeMin, depthRangeMax, minz, maxz);
 
890
                        }
 
891
                }
 
892
#endif
 
893
        }
 
894
}
 
895
 
 
896
void TransformDrawEngine::ApplyDrawStateLate() {
 
897
        // At this point, we know if the vertices are full alpha or not.
 
898
        // TODO: Set the nearest/linear here (since we correctly know if alpha/color tests are needed)?
 
899
        if (!gstate.isModeClear()) {
 
900
                if (gstate.isAlphaTestEnabled() || gstate.isColorTestEnabled()) {
 
901
                        fragmentTestCache_->BindTestTexture(GL_TEXTURE2);
 
902
                }
 
903
 
 
904
                textureCache_->ApplyTexture();
 
905
 
 
906
                if (fboTexNeedBind_) {
 
907
                        framebufferManager_->BindFramebufferColor(GL_TEXTURE1, gstate.getFrameBufRawAddress(), nullptr, BINDFBCOLOR_MAY_COPY_WITH_UV);
 
908
                        framebufferManager_->RebindFramebuffer();
 
909
 
 
910
                        glActiveTexture(GL_TEXTURE1);
 
911
                        // If we are rendering at a higher resolution, linear is probably best for the dest color.
 
912
                        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 
913
                        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 
914
                        glActiveTexture(GL_TEXTURE0);
 
915
                        fboTexBound_ = true;
 
916
                        fboTexNeedBind_ = false;
 
917
                }
 
918
        }
 
919
}