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 #include "ppsspp_config.h"
23 #include "StateMappingGLES.h"
24 #include "Common/Profiler/Profiler.h"
25 #include "Common/GPU/OpenGL/GLDebugLog.h"
26 #include "Common/GPU/OpenGL/GLRenderManager.h"
27 #include "Common/Data/Convert/SmallDataConvert.h"
28 
29 #include "GPU/Math3D.h"
30 #include "GPU/GPUState.h"
31 #include "GPU/ge_constants.h"
32 #include "Core/System.h"
33 #include "Core/Config.h"
34 #include "Core/Reporting.h"
35 #include "GPU/GLES/GPU_GLES.h"
36 #include "GPU/GLES/ShaderManagerGLES.h"
37 #include "GPU/GLES/TextureCacheGLES.h"
38 #include "GPU/GLES/FramebufferManagerGLES.h"
39 #include "GPU/Common/FragmentShaderGenerator.h"
40 
41 static const GLushort glBlendFactorLookup[(size_t)BlendFactor::COUNT] = {
42 	GL_ZERO,
43 	GL_ONE,
44 	GL_SRC_COLOR,
45 	GL_ONE_MINUS_SRC_COLOR,
46 	GL_DST_COLOR,
47 	GL_ONE_MINUS_DST_COLOR,
48 	GL_SRC_ALPHA,
49 	GL_ONE_MINUS_SRC_ALPHA,
50 	GL_DST_ALPHA,
51 	GL_ONE_MINUS_DST_ALPHA,
52 	GL_CONSTANT_COLOR,
53 	GL_ONE_MINUS_CONSTANT_COLOR,
54 	GL_CONSTANT_ALPHA,
55 	GL_ONE_MINUS_CONSTANT_ALPHA,
56 #if !defined(USING_GLES2)   // TODO: Remove when we have better headers
57 	GL_SRC1_COLOR,
58 	GL_ONE_MINUS_SRC1_COLOR,
59 	GL_SRC1_ALPHA,
60 	GL_ONE_MINUS_SRC1_ALPHA,
61 #elif !PPSSPP_PLATFORM(IOS)
62 	GL_SRC1_COLOR_EXT,
63 	GL_ONE_MINUS_SRC1_COLOR_EXT,
64 	GL_SRC1_ALPHA_EXT,
65 	GL_ONE_MINUS_SRC1_ALPHA_EXT,
66 #else
67 	GL_INVALID_ENUM,
68 	GL_INVALID_ENUM,
69 	GL_INVALID_ENUM,
70 	GL_INVALID_ENUM,
71 #endif
72 	GL_INVALID_ENUM,
73 };
74 
75 static const GLushort glBlendEqLookup[(size_t)BlendEq::COUNT] = {
76 	GL_FUNC_ADD,
77 	GL_FUNC_SUBTRACT,
78 	GL_FUNC_REVERSE_SUBTRACT,
79 	GL_MIN,
80 	GL_MAX,
81 };
82 
83 static const GLushort cullingMode[] = {
84 	GL_FRONT,
85 	GL_BACK,
86 };
87 
88 static const GLushort compareOps[] = {
89 	GL_NEVER, GL_ALWAYS, GL_EQUAL, GL_NOTEQUAL,
90 	GL_LESS, GL_LEQUAL, GL_GREATER, GL_GEQUAL,
91 };
92 
93 static const GLushort stencilOps[] = {
94 	GL_KEEP,
95 	GL_ZERO,
96 	GL_REPLACE,
97 	GL_INVERT,
98 	GL_INCR,
99 	GL_DECR,
100 	GL_KEEP, // reserved
101 	GL_KEEP, // reserved
102 };
103 
104 #if !defined(USING_GLES2)
105 static const GLushort logicOps[] = {
106 	GL_CLEAR,
107 	GL_AND,
108 	GL_AND_REVERSE,
109 	GL_COPY,
110 	GL_AND_INVERTED,
111 	GL_NOOP,
112 	GL_XOR,
113 	GL_OR,
114 	GL_NOR,
115 	GL_EQUIV,
116 	GL_INVERT,
117 	GL_OR_REVERSE,
118 	GL_COPY_INVERTED,
119 	GL_OR_INVERTED,
120 	GL_NAND,
121 	GL_SET,
122 };
123 #endif
124 
ResetFramebufferRead()125 inline void DrawEngineGLES::ResetFramebufferRead() {
126 	if (fboTexBound_) {
127 		GLRenderManager *renderManager = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
128 		renderManager->BindTexture(TEX_SLOT_SHADERBLEND_SRC, nullptr);
129 		fboTexBound_ = false;
130 	}
131 }
132 
ApplyDrawState(int prim)133 void DrawEngineGLES::ApplyDrawState(int prim) {
134 	GLRenderManager *renderManager = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
135 
136 	if (!gstate_c.IsDirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE)) {
137 		// Nothing to do, let's early-out
138 		return;
139 	}
140 
141 	// Start profiling here to skip SetTexture which is already accounted for
142 	PROFILE_THIS_SCOPE("applydrawstate");
143 
144 	bool useBufferedRendering = framebufferManager_->UseBufferedRendering();
145 
146 	if (gstate_c.IsDirty(DIRTY_BLEND_STATE)) {
147 		gstate_c.Clean(DIRTY_BLEND_STATE);
148 		gstate_c.SetAllowFramebufferRead(!g_Config.bDisableSlowFramebufEffects);
149 
150 		if (gstate.isModeClear()) {
151 			// Color Test
152 			bool colorMask = gstate.isClearModeColorMask();
153 			bool alphaMask = gstate.isClearModeAlphaMask();
154 			renderManager->SetNoBlendAndMask((colorMask ? 7 : 0) | (alphaMask ? 8 : 0));
155 		} else {
156 			// Do the large chunks of state conversion. We might be able to hide these two behind a dirty-flag each,
157 			// to avoid recomputing heavy stuff unnecessarily every draw call.
158 			GenericBlendState blendState;
159 			ConvertBlendState(blendState, gstate_c.allowFramebufferRead);
160 
161 			GenericMaskState maskState;
162 			ConvertMaskState(maskState, gstate_c.allowFramebufferRead);
163 
164 			if (blendState.applyFramebufferRead || maskState.applyFramebufferRead) {
165 				if (ApplyFramebufferRead(&fboTexNeedsBind_)) {
166 					// The shader takes over the responsibility for blending, so recompute.
167 					ApplyStencilReplaceAndLogicOpIgnoreBlend(blendState.replaceAlphaWithStencil, blendState);
168 
169 					// We copy the framebuffer here, as doing so will wipe any blend state if we do it later.
170 					if (fboTexNeedsBind_) {
171 						// Note that this is positions, not UVs, that we need the copy from.
172 						framebufferManager_->BindFramebufferAsColorTexture(1, framebufferManager_->GetCurrentRenderVFB(), BINDFBCOLOR_MAY_COPY);
173 						// If we are rendering at a higher resolution, linear is probably best for the dest color.
174 						renderManager->SetTextureSampler(1, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, GL_LINEAR, GL_LINEAR, 0.0f);
175 						fboTexBound_ = true;
176 						fboTexNeedsBind_ = false;
177 
178 						framebufferManager_->RebindFramebuffer("RebindFramebuffer - ApplyDrawState");
179 						// Must dirty blend state here so we re-copy next time.  Example: Lunar's spell effects.
180 						gstate_c.Dirty(DIRTY_BLEND_STATE);
181 					}
182 				} else {
183 					// Until next time, force it off.
184 					ResetFramebufferRead();
185 					gstate_c.SetAllowFramebufferRead(false);
186 				}
187 				gstate_c.Dirty(DIRTY_FRAGMENTSHADER_STATE);
188 			} else if (blendState.resetFramebufferRead) {
189 				ResetFramebufferRead();
190 			}
191 
192 			if (blendState.enabled) {
193 				if (blendState.dirtyShaderBlendFixValues) {
194 					// Not quite sure how necessary this is.
195 					gstate_c.Dirty(DIRTY_SHADERBLEND);
196 				}
197 				if (blendState.useBlendColor) {
198 					uint32_t color = blendState.blendColor;
199 					float col[4];
200 					Uint8x4ToFloat4(col, color);
201 					renderManager->SetBlendFactor(col);
202 				}
203 			}
204 
205 			int mask = (int)maskState.rgba[0] | ((int)maskState.rgba[1] << 1) | ((int)maskState.rgba[2] << 2) | ((int)maskState.rgba[3] << 3);
206 			if (blendState.enabled) {
207 				renderManager->SetBlendAndMask(mask, blendState.enabled,
208 					glBlendFactorLookup[(size_t)blendState.srcColor], glBlendFactorLookup[(size_t)blendState.dstColor],
209 					glBlendFactorLookup[(size_t)blendState.srcAlpha], glBlendFactorLookup[(size_t)blendState.dstAlpha],
210 					glBlendEqLookup[(size_t)blendState.eqColor], glBlendEqLookup[(size_t)blendState.eqAlpha]);
211 			} else {
212 				renderManager->SetNoBlendAndMask(mask);
213 			}
214 
215 #ifndef USING_GLES2
216 			if (gstate_c.Supports(GPU_SUPPORTS_LOGIC_OP)) {
217 				renderManager->SetLogicOp(gstate.isLogicOpEnabled() && gstate.getLogicOp() != GE_LOGIC_COPY,
218 					logicOps[gstate.getLogicOp()]);
219 			}
220 #endif
221 		}
222 	}
223 
224 	if (gstate_c.IsDirty(DIRTY_RASTER_STATE)) {
225 		gstate_c.Clean(DIRTY_RASTER_STATE);
226 
227 		// Dither
228 		bool dither = gstate.isDitherEnabled();
229 		bool cullEnable;
230 		GLenum cullMode = cullingMode[gstate.getCullMode() ^ !useBufferedRendering];
231 
232 		cullEnable = !gstate.isModeClear() && prim != GE_PRIM_RECTANGLES && gstate.isCullEnabled();
233 
234 		bool depthClampEnable = false;
235 		if (gstate.isModeClear() || gstate.isModeThrough()) {
236 			// TODO: Might happen in clear mode if not through...
237 			depthClampEnable = false;
238 		} else {
239 			if (gstate.getDepthRangeMin() == 0 || gstate.getDepthRangeMax() == 65535) {
240 				// TODO: Still has a bug where we clamp to depth range if one is not the full range.
241 				// But the alternate is not clamping in either direction...
242 				depthClampEnable = gstate.isDepthClampEnabled() && gstate_c.Supports(GPU_SUPPORTS_DEPTH_CLAMP);
243 			} else {
244 				// We just want to clip in this case, the clamp would be clipped anyway.
245 				depthClampEnable = false;
246 			}
247 		}
248 
249 		renderManager->SetRaster(cullEnable, GL_CCW, cullMode, dither, depthClampEnable);
250 	}
251 
252 	if (gstate_c.IsDirty(DIRTY_DEPTHSTENCIL_STATE)) {
253 		gstate_c.Clean(DIRTY_DEPTHSTENCIL_STATE);
254 		GenericStencilFuncState stencilState;
255 		ConvertStencilFuncState(stencilState);
256 
257 		if (gstate.isModeClear()) {
258 			// Depth Test
259 			if (gstate.isClearModeDepthMask()) {
260 				framebufferManager_->SetDepthUpdated();
261 			}
262 			renderManager->SetStencilFunc(gstate.isClearModeAlphaMask(), GL_ALWAYS, 0xFF, 0xFF);
263 			renderManager->SetStencilOp(stencilState.writeMask, GL_REPLACE, GL_REPLACE, GL_REPLACE);
264 			renderManager->SetDepth(true, gstate.isClearModeDepthMask() ? true : false, GL_ALWAYS);
265 		} else {
266 			// Depth Test
267 			renderManager->SetDepth(gstate.isDepthTestEnabled(), gstate.isDepthWriteEnabled(), compareOps[gstate.getDepthTestFunction()]);
268 			if (gstate.isDepthTestEnabled() && gstate.isDepthWriteEnabled()) {
269 				framebufferManager_->SetDepthUpdated();
270 			}
271 
272 			// Stencil Test
273 			if (stencilState.enabled) {
274 				renderManager->SetStencilFunc(stencilState.enabled, compareOps[stencilState.testFunc], stencilState.testRef, stencilState.testMask);
275 				renderManager->SetStencilOp(stencilState.writeMask, stencilOps[stencilState.sFail], stencilOps[stencilState.zFail], stencilOps[stencilState.zPass]);
276 			} else {
277 				renderManager->SetStencilDisabled();
278 			}
279 		}
280 	}
281 
282 	if (gstate_c.IsDirty(DIRTY_VIEWPORTSCISSOR_STATE)) {
283 		gstate_c.Clean(DIRTY_VIEWPORTSCISSOR_STATE);
284 		ConvertViewportAndScissor(useBufferedRendering,
285 			framebufferManager_->GetRenderWidth(), framebufferManager_->GetRenderHeight(),
286 			framebufferManager_->GetTargetBufferWidth(), framebufferManager_->GetTargetBufferHeight(),
287 			vpAndScissor);
288 
289 		renderManager->SetScissor(GLRect2D{ vpAndScissor.scissorX, vpAndScissor.scissorY, vpAndScissor.scissorW, vpAndScissor.scissorH });
290 		renderManager->SetViewport({
291 			vpAndScissor.viewportX, vpAndScissor.viewportY,
292 			vpAndScissor.viewportW, vpAndScissor.viewportH,
293 			vpAndScissor.depthRangeMin, vpAndScissor.depthRangeMax });
294 
295 		if (vpAndScissor.dirtyProj) {
296 			gstate_c.Dirty(DIRTY_PROJMATRIX);
297 		}
298 		if (vpAndScissor.dirtyDepth) {
299 			gstate_c.Dirty(DIRTY_DEPTHRANGE);
300 		}
301 	}
302 }
303 
ApplyDrawStateLate(bool setStencilValue,int stencilValue)304 void DrawEngineGLES::ApplyDrawStateLate(bool setStencilValue, int stencilValue) {
305 	if (setStencilValue) {
306 		render_->SetStencilFunc(GL_TRUE, GL_ALWAYS, stencilValue, 255);
307 	}
308 
309 	// At this point, we know if the vertices are full alpha or not.
310 	// TODO: Set the nearest/linear here (since we correctly know if alpha/color tests are needed)?
311 	if (!gstate.isModeClear()) {
312 		// Apply last, once we know the alpha params of the texture.
313 		if (gstate.isAlphaTestEnabled() || gstate.isColorTestEnabled()) {
314 			fragmentTestCache_->BindTestTexture(TEX_SLOT_ALPHATEST);
315 		}
316 	}
317 }
318