Bug Summary

File:Source/Plugins/Plugin_VideoOGL/Src/Render.cpp
Location:line 450, column 3
Description:Value stored to 'bSuccess' is never read

Annotated Source Code

1// Copyright 2013 Dolphin Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include "Globals.h"
6#include "Thread.h"
7#include "Atomic.h"
8
9#include <vector>
10#include <cmath>
11#include <cstdio>
12
13#include "GLUtil.h"
14#if defined(HAVE_WX1) && HAVE_WX1
15#include "WxUtils.h"
16#endif
17
18#include "FileUtil.h"
19
20#ifdef _WIN32
21#include <mmsystem.h>
22#endif
23
24#include "CommonPaths.h"
25#include "DriverDetails.h"
26#include "VideoConfig.h"
27#include "Statistics.h"
28#include "ImageWrite.h"
29#include "PixelEngine.h"
30#include "Render.h"
31#include "OpcodeDecoding.h"
32#include "BPStructs.h"
33#include "TextureCache.h"
34#include "RasterFont.h"
35#include "VertexShaderGen.h"
36#include "DLCache.h"
37#include "PixelShaderManager.h"
38#include "ProgramShaderCache.h"
39#include "VertexShaderManager.h"
40#include "VertexLoaderManager.h"
41#include "VertexLoader.h"
42#include "PostProcessing.h"
43#include "TextureConverter.h"
44#include "OnScreenDisplay.h"
45#include "Timer.h"
46#include "StringUtil.h"
47#include "FramebufferManager.h"
48#include "Fifo.h"
49#include "Debugger.h"
50#include "Core.h"
51#include "Movie.h"
52#include "Host.h"
53#include "BPFunctions.h"
54#include "FPSCounter.h"
55#include "ConfigManager.h"
56#include "VertexManager.h"
57#include "SamplerCache.h"
58#include "StreamBuffer.h"
59
60#include "main.h" // Local
61#ifdef _WIN32
62#include "EmuWindow.h"
63#endif
64#if defined _WIN32 || defined HAVE_LIBAV
65#include "AVIDump.h"
66#endif
67
68#if defined(HAVE_WX1) && HAVE_WX1
69#include <wx/image.h>
70#endif
71
72// glew1.8 doesn't define KHR_debug
73#ifndef GL_DEBUG_OUTPUT0x92E0
74#define GL_DEBUG_OUTPUT0x92E0 0x92E0
75#endif
76
77
78void VideoConfig::UpdateProjectionHack()
79{
80 ::UpdateProjectionHack(g_Config.iPhackvalue, g_Config.sPhackvalue);
81}
82
83
84#if defined(HAVE_WX1) && HAVE_WX1
85// Screenshot thread struct
86typedef struct
87{
88 int W, H;
89 std::string filename;
90 wxImage *img;
91} ScrStrct;
92#endif
93
94
95int OSDInternalW, OSDInternalH;
96
97namespace OGL
98{
99
100enum MultisampleMode {
101 MULTISAMPLE_OFF,
102 MULTISAMPLE_2X,
103 MULTISAMPLE_4X,
104 MULTISAMPLE_8X,
105 MULTISAMPLE_CSAA_8X,
106 MULTISAMPLE_CSAA_8XQ,
107 MULTISAMPLE_CSAA_16X,
108 MULTISAMPLE_CSAA_16XQ,
109 MULTISAMPLE_SSAA_4X,
110};
111
112
113VideoConfig g_ogl_config;
114
115// Declarations and definitions
116// ----------------------------
117static int s_fps = 0;
118static GLuint s_ShowEFBCopyRegions_VBO = 0;
119static GLuint s_ShowEFBCopyRegions_VAO = 0;
120static SHADER s_ShowEFBCopyRegions;
121
122static RasterFont* s_pfont = NULL__null;
123
124// 1 for no MSAA. Use s_MSAASamples > 1 to check for MSAA.
125static int s_MSAASamples = 1;
126static int s_MSAACoverageSamples = 0;
127static int s_LastMultisampleMode = 0;
128
129static u32 s_blendMode;
130
131static bool s_vsync;
132
133#if defined(HAVE_WX1) && HAVE_WX1
134static std::thread scrshotThread;
135#endif
136
137// EFB cache related
138static const u32 EFB_CACHE_RECT_SIZE = 64; // Cache 64x64 blocks.
139static const u32 EFB_CACHE_WIDTH = (EFB_WIDTH + EFB_CACHE_RECT_SIZE - 1) / EFB_CACHE_RECT_SIZE; // round up
140static const u32 EFB_CACHE_HEIGHT = (EFB_HEIGHT + EFB_CACHE_RECT_SIZE - 1) / EFB_CACHE_RECT_SIZE;
141static bool s_efbCacheValid[2][EFB_CACHE_WIDTH * EFB_CACHE_HEIGHT];
142static std::vector<u32> s_efbCache[2][EFB_CACHE_WIDTH * EFB_CACHE_HEIGHT]; // 2 for PEEK_Z and PEEK_COLOR
143
144int GetNumMSAASamples(int MSAAMode)
145{
146 int samples;
147 switch (MSAAMode)
148 {
149 case MULTISAMPLE_OFF:
150 samples = 1;
151 break;
152
153 case MULTISAMPLE_2X:
154 samples = 2;
155 break;
156
157 case MULTISAMPLE_4X:
158 case MULTISAMPLE_CSAA_8X:
159 case MULTISAMPLE_CSAA_16X:
160 case MULTISAMPLE_SSAA_4X:
161 samples = 4;
162 break;
163
164 case MULTISAMPLE_8X:
165 case MULTISAMPLE_CSAA_8XQ:
166 case MULTISAMPLE_CSAA_16XQ:
167 samples = 8;
168 break;
169
170 default:
171 samples = 1;
172 }
173
174 if(samples <= g_ogl_config.max_samples) return samples;
175
176 ERROR_LOG(VIDEO, "MSAA Bug: %d samples selected, but only %d supported by GPU.", samples, g_ogl_config.max_samples)do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 176, "MSAA Bug: %d samples selected, but only %d supported by GPU."
, samples, g_ogl_config.max_samples); } } while (0)
;
177 return g_ogl_config.max_samples;
178}
179
180int GetNumMSAACoverageSamples(int MSAAMode)
181{
182 int samples;
183 switch (g_ActiveConfig.iMultisampleMode)
184 {
185 case MULTISAMPLE_CSAA_8X:
186 case MULTISAMPLE_CSAA_8XQ:
187 samples = 8;
188 break;
189
190 case MULTISAMPLE_CSAA_16X:
191 case MULTISAMPLE_CSAA_16XQ:
192 samples = 16;
193 break;
194
195 default:
196 samples = 0;
197 }
198 if(g_ogl_config.bSupportCoverageMSAA || samples == 0) return samples;
199
200 ERROR_LOG(VIDEO, "MSAA Bug: CSAA selected, but not supported by GPU.")do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 200, "MSAA Bug: CSAA selected, but not supported by GPU.");
} } while (0)
;
201 return 0;
202}
203
204void ApplySSAASettings() {
205 // GLES3 doesn't support SSAA
206#ifndef USE_GLES3
207 if(g_ActiveConfig.iMultisampleMode == MULTISAMPLE_SSAA_4X) {
208 if(g_ogl_config.bSupportSampleShading) {
209 glEnable(GL_SAMPLE_SHADING_ARB0x8C36);
210 glMinSampleShadingARB__glewMinSampleShadingARB(s_MSAASamples);
211 } else {
212 ERROR_LOG(VIDEO, "MSAA Bug: SSAA selected, but not supported by GPU.")do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 212, "MSAA Bug: SSAA selected, but not supported by GPU.");
} } while (0)
;
213 }
214 } else if(g_ogl_config.bSupportSampleShading) {
215 glDisable(GL_SAMPLE_SHADING_ARB0x8C36);
216 }
217#endif
218}
219
220void GLAPIENTRY ErrorCallback( GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const char* message, void* userParam)
221{
222 // GLES3 doesn't natively support this
223 // XXX: Include GLES2 extensions header so we can use this
224#ifndef USE_GLES3
225 const char *s_source;
226 const char *s_type;
227
228 switch(source)
229 {
230 case GL_DEBUG_SOURCE_API_ARB0x8246: s_source = "API"; break;
231 case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB0x8247: s_source = "Window System"; break;
232 case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB0x8248: s_source = "Shader Compiler"; break;
233 case GL_DEBUG_SOURCE_THIRD_PARTY_ARB0x8249: s_source = "Third Party"; break;
234 case GL_DEBUG_SOURCE_APPLICATION_ARB0x824A: s_source = "Application"; break;
235 case GL_DEBUG_SOURCE_OTHER_ARB0x824B: s_source = "Other"; break;
236 default: s_source = "Unknown"; break;
237 }
238 switch(type)
239 {
240 case GL_DEBUG_TYPE_ERROR_ARB0x824C: s_type = "Error"; break;
241 case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB0x824D: s_type = "Deprecated"; break;
242 case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB0x824E: s_type = "Undefined"; break;
243 case GL_DEBUG_TYPE_PORTABILITY_ARB0x824F: s_type = "Portability"; break;
244 case GL_DEBUG_TYPE_PERFORMANCE_ARB0x8250: s_type = "Performance"; break;
245 case GL_DEBUG_TYPE_OTHER_ARB0x8251: s_type = "Other"; break;
246 default: s_type = "Unknown"; break;
247 }
248 switch(severity)
249 {
250 case GL_DEBUG_SEVERITY_HIGH_ARB0x9146: ERROR_LOG(VIDEO, "id: %x, source: %s, type: %s - %s", id, s_source, s_type, message)do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 250, "id: %x, source: %s, type: %s - %s", id, s_source, s_type
, message); } } while (0)
; break;
251 case GL_DEBUG_SEVERITY_MEDIUM_ARB0x9147: WARN_LOG(VIDEO, "id: %x, source: %s, type: %s - %s", id, s_source, s_type, message)do { { if (LogTypes::LWARNING <= 3) GenericLog(LogTypes::LWARNING
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 251, "id: %x, source: %s, type: %s - %s", id, s_source, s_type
, message); } } while (0)
; break;
252 case GL_DEBUG_SEVERITY_LOW_ARB0x9148: WARN_LOG(VIDEO, "id: %x, source: %s, type: %s - %s", id, s_source, s_type, message)do { { if (LogTypes::LWARNING <= 3) GenericLog(LogTypes::LWARNING
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 252, "id: %x, source: %s, type: %s - %s", id, s_source, s_type
, message); } } while (0)
; break;
253 default: ERROR_LOG(VIDEO, "id: %x, source: %s, type: %s - %s", id, s_source, s_type, message)do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 253, "id: %x, source: %s, type: %s - %s", id, s_source, s_type
, message); } } while (0)
; break;
254 }
255#endif
256}
257
258#ifndef USE_GLES3
259// Two small Fallbacks to avoid GL_ARB_ES2_compatibility
260void GLAPIENTRY DepthRangef(GLfloat neardepth, GLfloat fardepth)
261{
262 glDepthRange(neardepth, fardepth);
263}
264void GLAPIENTRY ClearDepthf(GLfloat depthval)
265{
266 glClearDepth(depthval);
267}
268#endif
269
270void InitDriverInfo()
271{
272 // Get Vendor
273 std::string svendor = std::string(g_ogl_config.gl_vendor);
274 std::string srenderer = std::string(g_ogl_config.gl_renderer);
275 DriverDetails::Vendor vendor = DriverDetails::VENDOR_UNKNOWN;
276 u32 devfamily = 0;
277 double version = 0.0;
278
279 // Get Vendor first
280 if (svendor == "NVIDIA Corporation" && srenderer != "NVIDIA Tegra")
281 vendor = DriverDetails::VENDOR_NVIDIA;
282 else if (svendor == "ATI Technologies Inc.")
283 vendor = DriverDetails::VENDOR_ATI;
284 else if (std::string::npos != svendor.find("Intel"))
285 vendor = DriverDetails::VENDOR_INTEL;
286 else if (svendor == "ARM")
287 vendor = DriverDetails::VENDOR_ARM;
288 else if (svendor == "Qualcomm")
289 vendor = DriverDetails::VENDOR_QUALCOMM;
290 else if (svendor == "Imagination Technologies")
291 vendor = DriverDetails::VENDOR_IMGTEC;
292 else if (svendor == "NVIDIA Corporation" && srenderer == "NVIDIA Tegra")
293 vendor = DriverDetails::VENDOR_TEGRA;
294 else if (svendor == "Vivante Corporation")
295 vendor = DriverDetails::VENDOR_VIVANTE;
296
297 // Get device family and driver version...if we care about it
298 switch(vendor)
299 {
300 case DriverDetails::VENDOR_QUALCOMM:
301 {
302 if (std::string::npos != srenderer.find("Adreno (TM) 3"))
303 devfamily = 300;
304 else
305 devfamily = 200;
306 double glVersion;
307 sscanf(g_ogl_config.gl_version, "OpenGL ES %lg V@%lg", &glVersion, &version);
308 }
309 break;
310 // We don't care about these
311 default:
312 break;
313 }
314 DriverDetails::Init(vendor, devfamily, version);
315}
316
317// Init functions
318Renderer::Renderer()
319{
320 OSDInternalW = 0;
321 OSDInternalH = 0;
322
323 s_fps=0;
324 s_ShowEFBCopyRegions_VBO = 0;
325 s_blendMode = 0;
326 InitFPSCounter();
327
328 bool bSuccess = true;
329
330 g_ogl_config.gl_vendor = (const char*)glGetString(GL_VENDOR0x1F00);
331 g_ogl_config.gl_renderer = (const char*)glGetString(GL_RENDERER0x1F01);
332 g_ogl_config.gl_version = (const char*)glGetString(GL_VERSION0x1F02);
333 g_ogl_config.glsl_version = (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION0x8B8C);
334
335 InitDriverInfo();
336
337 // Init extension support.
338#ifdef USE_GLES3
339 // Set default GLES3 options
340 GLFunc::Init();
341 WARN_LOG(VIDEO, "Running the OpenGL ES 3 backend!")do { { if (LogTypes::LWARNING <= 3) GenericLog(LogTypes::LWARNING
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 341, "Running the OpenGL ES 3 backend!"); } } while (0)
;
342 g_Config.backend_info.bSupportsDualSourceBlend = false;
343 g_Config.backend_info.bSupportsGLSLUBO = true;
344 g_Config.backend_info.bSupportsPrimitiveRestart = false;
345
346 g_ogl_config.bSupportsGLSLCache = false; // XXX: Reenable once shaders compile correctly
347 g_ogl_config.bSupportsGLPinnedMemory = false;
348 g_ogl_config.bSupportsGLSync = true;
349 g_ogl_config.bSupportsGLBaseVertex = false;
350 g_ogl_config.bSupportCoverageMSAA = false; // XXX: GLES3 spec has MSAA
351 g_ogl_config.bSupportSampleShading = false;
352 g_ogl_config.bSupportOGL31 = false;
353 g_ogl_config.eSupportedGLSLVersion = GLSLES3;
354#else
355 GLint numvertexattribs = 0;
356 glGetIntegerv(GL_MAX_VERTEX_ATTRIBS0x8869, &numvertexattribs);
357 if (numvertexattribs < 16)
358 {
359 ERROR_LOG(VIDEO, "GPU: OGL ERROR: Number of attributes %d not enough.\n"do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 361, "GPU: OGL ERROR: Number of attributes %d not enough.\n"
"GPU: Does your video card support OpenGL 2.x?", numvertexattribs
); } } while (0)
360 "GPU: Does your video card support OpenGL 2.x?",do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 361, "GPU: OGL ERROR: Number of attributes %d not enough.\n"
"GPU: Does your video card support OpenGL 2.x?", numvertexattribs
); } } while (0)
361 numvertexattribs)do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 361, "GPU: OGL ERROR: Number of attributes %d not enough.\n"
"GPU: Does your video card support OpenGL 2.x?", numvertexattribs
); } } while (0)
;
362 bSuccess = false;
363 }
364#ifdef __APPLE__
365 glewExperimental = 1;
366#endif
367 if (glewInit() != GLEW_OK0)
368 {
369 ERROR_LOG(VIDEO, "glewInit() failed! Does your video card support OpenGL 2.x?")do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 369, "glewInit() failed! Does your video card support OpenGL 2.x?"
); } } while (0)
;
370 return; // TODO: fail
371 }
372
373#if defined(_DEBUG) || defined(DEBUGFAST)
374 if (GLEW_ARB_debug_output(*(const GLboolean*)&__GLEW_ARB_debug_output))
375 {
376 glDebugMessageControlARB__glewDebugMessageControlARB(GL_DONT_CARE0x1100, GL_DONT_CARE0x1100, GL_DONT_CARE0x1100, 0, NULL__null, true);
377 glDebugMessageCallbackARB__glewDebugMessageCallbackARB( ErrorCallback, NULL__null );
378 glEnable( GL_DEBUG_OUTPUT0x92E0 );
379 }
380#endif
381
382 if (!GLEW_EXT_secondary_color(*(const GLboolean*)&__GLEW_EXT_secondary_color))
383 {
384 ERROR_LOG(VIDEO, "GPU: OGL ERROR: Need GL_EXT_secondary_color.\n"do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 385, "GPU: OGL ERROR: Need GL_EXT_secondary_color.\n" "GPU: Does your video card support OpenGL 2.x?"
); } } while (0)
385 "GPU: Does your video card support OpenGL 2.x?")do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 385, "GPU: OGL ERROR: Need GL_EXT_secondary_color.\n" "GPU: Does your video card support OpenGL 2.x?"
); } } while (0)
;
386 bSuccess = false;
387 }
388
389 if (!GLEW_ARB_framebuffer_object(*(const GLboolean*)&__GLEW_ARB_framebuffer_object))
390 {
391 ERROR_LOG(VIDEO, "GPU: ERROR: Need GL_ARB_framebuffer_object for multiple render targets.\n"do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 392, "GPU: ERROR: Need GL_ARB_framebuffer_object for multiple render targets.\n"
"GPU: Does your video card support OpenGL 3.0?"); } } while (
0)
392 "GPU: Does your video card support OpenGL 3.0?")do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 392, "GPU: ERROR: Need GL_ARB_framebuffer_object for multiple render targets.\n"
"GPU: Does your video card support OpenGL 3.0?"); } } while (
0)
;
393 bSuccess = false;
394 }
395
396 if (!GLEW_ARB_vertex_array_object(*(const GLboolean*)&__GLEW_ARB_vertex_array_object))
397 {
398 ERROR_LOG(VIDEO, "GPU: OGL ERROR: Need GL_ARB_vertex_array_object.\n"do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 399, "GPU: OGL ERROR: Need GL_ARB_vertex_array_object.\n" "GPU: Does your video card support OpenGL 3.0?"
); } } while (0)
399 "GPU: Does your video card support OpenGL 3.0?")do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 399, "GPU: OGL ERROR: Need GL_ARB_vertex_array_object.\n" "GPU: Does your video card support OpenGL 3.0?"
); } } while (0)
;
400 bSuccess = false;
401 }
402
403 if (!GLEW_ARB_map_buffer_range(*(const GLboolean*)&__GLEW_ARB_map_buffer_range))
404 {
405 ERROR_LOG(VIDEO, "GPU: OGL ERROR: Need GL_ARB_map_buffer_range.\n"do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 406, "GPU: OGL ERROR: Need GL_ARB_map_buffer_range.\n" "GPU: Does your video card support OpenGL 3.0?"
); } } while (0)
406 "GPU: Does your video card support OpenGL 3.0?")do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 406, "GPU: OGL ERROR: Need GL_ARB_map_buffer_range.\n" "GPU: Does your video card support OpenGL 3.0?"
); } } while (0)
;
407 bSuccess = false;
408 }
409
410 if (!GLEW_ARB_sampler_objects(*(const GLboolean*)&__GLEW_ARB_sampler_objects) && bSuccess)
411 {
412 ERROR_LOG(VIDEO, "GPU: OGL ERROR: Need GL_ARB_sampler_objects."do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 414, "GPU: OGL ERROR: Need GL_ARB_sampler_objects." "GPU: Does your video card support OpenGL 3.2?"
"Please report this issue, then there will be a workaround")
; } } while (0)
413 "GPU: Does your video card support OpenGL 3.2?"do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 414, "GPU: OGL ERROR: Need GL_ARB_sampler_objects." "GPU: Does your video card support OpenGL 3.2?"
"Please report this issue, then there will be a workaround")
; } } while (0)
414 "Please report this issue, then there will be a workaround")do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 414, "GPU: OGL ERROR: Need GL_ARB_sampler_objects." "GPU: Does your video card support OpenGL 3.2?"
"Please report this issue, then there will be a workaround")
; } } while (0)
;
415 bSuccess = false;
416 }
417 if (!GLEW_ARB_texture_non_power_of_two(*(const GLboolean*)&__GLEW_ARB_texture_non_power_of_two))
418 WARN_LOG(VIDEO, "ARB_texture_non_power_of_two not supported.")do { { if (LogTypes::LWARNING <= 3) GenericLog(LogTypes::LWARNING
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 418, "ARB_texture_non_power_of_two not supported."); } } while
(0)
;
419
420 // OpenGL 3 doesn't provide GLES like float functions for depth.
421 // They are in core in OpenGL 4.1, so almost every driver should support them.
422 // But for the oldest ones, we provide fallbacks to the old double functions.
423 if (!GLEW_ARB_ES2_compatibility(*(const GLboolean*)&__GLEW_ARB_ES2_compatibility))
424 {
425 glDepthRangef__glewDepthRangef = DepthRangef;
426 glClearDepthf__glewClearDepthf = ClearDepthf;
427
428 }
429
430 if (!bSuccess)
431 return; // TODO: fail
432
433 g_Config.backend_info.bSupportsDualSourceBlend = GLEW_ARB_blend_func_extended(*(const GLboolean*)&__GLEW_ARB_blend_func_extended);
434 g_Config.backend_info.bSupportsGLSLUBO = GLEW_ARB_uniform_buffer_object(*(const GLboolean*)&__GLEW_ARB_uniform_buffer_object);
435 g_Config.backend_info.bSupportsPrimitiveRestart = GLEW_VERSION_3_1(*(const GLboolean*)&__GLEW_VERSION_3_1) || GLEW_NV_primitive_restart(*(const GLboolean*)&__GLEW_NV_primitive_restart);
436
437 g_ogl_config.bSupportsGLSLCache = GLEW_ARB_get_program_binary(*(const GLboolean*)&__GLEW_ARB_get_program_binary);
438 g_ogl_config.bSupportsGLPinnedMemory = GLEW_AMD_pinned_memory(*(const GLboolean*)&__GLEW_AMD_pinned_memory);
439 g_ogl_config.bSupportsGLSync = GLEW_ARB_sync(*(const GLboolean*)&__GLEW_ARB_sync);
440 g_ogl_config.bSupportsGLBaseVertex = GLEW_ARB_draw_elements_base_vertex(*(const GLboolean*)&__GLEW_ARB_draw_elements_base_vertex
)
;
441 g_ogl_config.bSupportCoverageMSAA = GLEW_NV_framebuffer_multisample_coverage(*(const GLboolean*)&__GLEW_NV_framebuffer_multisample_coverage
)
;
442 g_ogl_config.bSupportSampleShading = GLEW_ARB_sample_shading(*(const GLboolean*)&__GLEW_ARB_sample_shading);
443 g_ogl_config.bSupportOGL31 = GLEW_VERSION_3_1(*(const GLboolean*)&__GLEW_VERSION_3_1);
444
445 if(strstr(g_ogl_config.glsl_version, "1.00") || strstr(g_ogl_config.glsl_version, "1.10"))
446 {
447 ERROR_LOG(VIDEO, "GPU: OGL ERROR: Need at least GLSL 1.20\n"do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 449, "GPU: OGL ERROR: Need at least GLSL 1.20\n" "GPU: Does your video card support OpenGL 2.1?\n"
"GPU: Your driver supports GLSL %s", g_ogl_config.glsl_version
); } } while (0)
448 "GPU: Does your video card support OpenGL 2.1?\n"do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 449, "GPU: OGL ERROR: Need at least GLSL 1.20\n" "GPU: Does your video card support OpenGL 2.1?\n"
"GPU: Your driver supports GLSL %s", g_ogl_config.glsl_version
); } } while (0)
449 "GPU: Your driver supports GLSL %s", g_ogl_config.glsl_version)do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 449, "GPU: OGL ERROR: Need at least GLSL 1.20\n" "GPU: Does your video card support OpenGL 2.1?\n"
"GPU: Your driver supports GLSL %s", g_ogl_config.glsl_version
); } } while (0)
;
450 bSuccess = false;
Value stored to 'bSuccess' is never read
451 }
452 else if(strstr(g_ogl_config.glsl_version, "1.20"))
453 {
454 g_ogl_config.eSupportedGLSLVersion = GLSL_120;
455 g_Config.backend_info.bSupportsDualSourceBlend = false; //TODO: implement dual source blend
456 }
457 else if(strstr(g_ogl_config.glsl_version, "1.30"))
458 {
459 g_ogl_config.eSupportedGLSLVersion = GLSL_130;
460 }
461 else
462 {
463 g_ogl_config.eSupportedGLSLVersion = GLSL_140;
464 }
465#endif
466
467 glGetIntegerv(GL_MAX_SAMPLES0x8D57, &g_ogl_config.max_samples);
468 if(g_ogl_config.max_samples < 1)
469 g_ogl_config.max_samples = 1;
470
471 if(g_Config.backend_info.bSupportsGLSLUBO && (
472 // hd3000 get corruption, hd4000 also and a big slowdown
473 !strcmp(g_ogl_config.gl_vendor, "Intel Open Source Technology Center") && (
474 !strcmp(g_ogl_config.gl_version, "3.0 Mesa 9.0.0") ||
475 !strcmp(g_ogl_config.gl_version, "3.0 Mesa 9.0.1") ||
476 !strcmp(g_ogl_config.gl_version, "3.0 Mesa 9.0.2") ||
477 !strcmp(g_ogl_config.gl_version, "3.0 Mesa 9.0.3") ||
478 !strcmp(g_ogl_config.gl_version, "3.0 Mesa 9.1.0") ||
479 !strcmp(g_ogl_config.gl_version, "3.0 Mesa 9.1.1") )
480 )) {
481 g_Config.backend_info.bSupportsGLSLUBO = false;
482 ERROR_LOG(VIDEO, "Buggy driver detected. Disable UBO")do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 482, "Buggy driver detected. Disable UBO"); } } while (0)
;
483 }
484
485 UpdateActiveConfig();
486
487 OSD::AddMessage(StringFromFormat("Video Info: %s, %s, %s",
488 g_ogl_config.gl_vendor,
489 g_ogl_config.gl_renderer,
490 g_ogl_config.gl_version).c_str(), 5000);
491
492 WARN_LOG(VIDEO,"Missing OGL Extensions: %s%s%s%s%s%s%s%s%s",do { { if (LogTypes::LWARNING <= 3) GenericLog(LogTypes::LWARNING
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 502, "Missing OGL Extensions: %s%s%s%s%s%s%s%s%s", g_ActiveConfig
.backend_info.bSupportsDualSourceBlend ? "" : "DualSourceBlend "
, g_ActiveConfig.backend_info.bSupportsGLSLUBO ? "" : "UniformBuffer "
, g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? "" :
"PrimitiveRestart ", g_ogl_config.bSupportsGLPinnedMemory ? ""
: "PinnedMemory ", g_ogl_config.bSupportsGLSLCache ? "" : "ShaderCache "
, g_ogl_config.bSupportsGLBaseVertex ? "" : "BaseVertex ", g_ogl_config
.bSupportsGLSync ? "" : "Sync ", g_ogl_config.bSupportCoverageMSAA
? "" : "CSAA ", g_ogl_config.bSupportSampleShading ? "" : "SSAA "
); } } while (0)
493 g_ActiveConfig.backend_info.bSupportsDualSourceBlend ? "" : "DualSourceBlend ",do { { if (LogTypes::LWARNING <= 3) GenericLog(LogTypes::LWARNING
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 502, "Missing OGL Extensions: %s%s%s%s%s%s%s%s%s", g_ActiveConfig
.backend_info.bSupportsDualSourceBlend ? "" : "DualSourceBlend "
, g_ActiveConfig.backend_info.bSupportsGLSLUBO ? "" : "UniformBuffer "
, g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? "" :
"PrimitiveRestart ", g_ogl_config.bSupportsGLPinnedMemory ? ""
: "PinnedMemory ", g_ogl_config.bSupportsGLSLCache ? "" : "ShaderCache "
, g_ogl_config.bSupportsGLBaseVertex ? "" : "BaseVertex ", g_ogl_config
.bSupportsGLSync ? "" : "Sync ", g_ogl_config.bSupportCoverageMSAA
? "" : "CSAA ", g_ogl_config.bSupportSampleShading ? "" : "SSAA "
); } } while (0)
494 g_ActiveConfig.backend_info.bSupportsGLSLUBO ? "" : "UniformBuffer ",do { { if (LogTypes::LWARNING <= 3) GenericLog(LogTypes::LWARNING
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 502, "Missing OGL Extensions: %s%s%s%s%s%s%s%s%s", g_ActiveConfig
.backend_info.bSupportsDualSourceBlend ? "" : "DualSourceBlend "
, g_ActiveConfig.backend_info.bSupportsGLSLUBO ? "" : "UniformBuffer "
, g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? "" :
"PrimitiveRestart ", g_ogl_config.bSupportsGLPinnedMemory ? ""
: "PinnedMemory ", g_ogl_config.bSupportsGLSLCache ? "" : "ShaderCache "
, g_ogl_config.bSupportsGLBaseVertex ? "" : "BaseVertex ", g_ogl_config
.bSupportsGLSync ? "" : "Sync ", g_ogl_config.bSupportCoverageMSAA
? "" : "CSAA ", g_ogl_config.bSupportSampleShading ? "" : "SSAA "
); } } while (0)
495 g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? "" : "PrimitiveRestart ",do { { if (LogTypes::LWARNING <= 3) GenericLog(LogTypes::LWARNING
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 502, "Missing OGL Extensions: %s%s%s%s%s%s%s%s%s", g_ActiveConfig
.backend_info.bSupportsDualSourceBlend ? "" : "DualSourceBlend "
, g_ActiveConfig.backend_info.bSupportsGLSLUBO ? "" : "UniformBuffer "
, g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? "" :
"PrimitiveRestart ", g_ogl_config.bSupportsGLPinnedMemory ? ""
: "PinnedMemory ", g_ogl_config.bSupportsGLSLCache ? "" : "ShaderCache "
, g_ogl_config.bSupportsGLBaseVertex ? "" : "BaseVertex ", g_ogl_config
.bSupportsGLSync ? "" : "Sync ", g_ogl_config.bSupportCoverageMSAA
? "" : "CSAA ", g_ogl_config.bSupportSampleShading ? "" : "SSAA "
); } } while (0)
496 g_ogl_config.bSupportsGLPinnedMemory ? "" : "PinnedMemory ",do { { if (LogTypes::LWARNING <= 3) GenericLog(LogTypes::LWARNING
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 502, "Missing OGL Extensions: %s%s%s%s%s%s%s%s%s", g_ActiveConfig
.backend_info.bSupportsDualSourceBlend ? "" : "DualSourceBlend "
, g_ActiveConfig.backend_info.bSupportsGLSLUBO ? "" : "UniformBuffer "
, g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? "" :
"PrimitiveRestart ", g_ogl_config.bSupportsGLPinnedMemory ? ""
: "PinnedMemory ", g_ogl_config.bSupportsGLSLCache ? "" : "ShaderCache "
, g_ogl_config.bSupportsGLBaseVertex ? "" : "BaseVertex ", g_ogl_config
.bSupportsGLSync ? "" : "Sync ", g_ogl_config.bSupportCoverageMSAA
? "" : "CSAA ", g_ogl_config.bSupportSampleShading ? "" : "SSAA "
); } } while (0)
497 g_ogl_config.bSupportsGLSLCache ? "" : "ShaderCache ",do { { if (LogTypes::LWARNING <= 3) GenericLog(LogTypes::LWARNING
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 502, "Missing OGL Extensions: %s%s%s%s%s%s%s%s%s", g_ActiveConfig
.backend_info.bSupportsDualSourceBlend ? "" : "DualSourceBlend "
, g_ActiveConfig.backend_info.bSupportsGLSLUBO ? "" : "UniformBuffer "
, g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? "" :
"PrimitiveRestart ", g_ogl_config.bSupportsGLPinnedMemory ? ""
: "PinnedMemory ", g_ogl_config.bSupportsGLSLCache ? "" : "ShaderCache "
, g_ogl_config.bSupportsGLBaseVertex ? "" : "BaseVertex ", g_ogl_config
.bSupportsGLSync ? "" : "Sync ", g_ogl_config.bSupportCoverageMSAA
? "" : "CSAA ", g_ogl_config.bSupportSampleShading ? "" : "SSAA "
); } } while (0)
498 g_ogl_config.bSupportsGLBaseVertex ? "" : "BaseVertex ",do { { if (LogTypes::LWARNING <= 3) GenericLog(LogTypes::LWARNING
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 502, "Missing OGL Extensions: %s%s%s%s%s%s%s%s%s", g_ActiveConfig
.backend_info.bSupportsDualSourceBlend ? "" : "DualSourceBlend "
, g_ActiveConfig.backend_info.bSupportsGLSLUBO ? "" : "UniformBuffer "
, g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? "" :
"PrimitiveRestart ", g_ogl_config.bSupportsGLPinnedMemory ? ""
: "PinnedMemory ", g_ogl_config.bSupportsGLSLCache ? "" : "ShaderCache "
, g_ogl_config.bSupportsGLBaseVertex ? "" : "BaseVertex ", g_ogl_config
.bSupportsGLSync ? "" : "Sync ", g_ogl_config.bSupportCoverageMSAA
? "" : "CSAA ", g_ogl_config.bSupportSampleShading ? "" : "SSAA "
); } } while (0)
499 g_ogl_config.bSupportsGLSync ? "" : "Sync ",do { { if (LogTypes::LWARNING <= 3) GenericLog(LogTypes::LWARNING
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 502, "Missing OGL Extensions: %s%s%s%s%s%s%s%s%s", g_ActiveConfig
.backend_info.bSupportsDualSourceBlend ? "" : "DualSourceBlend "
, g_ActiveConfig.backend_info.bSupportsGLSLUBO ? "" : "UniformBuffer "
, g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? "" :
"PrimitiveRestart ", g_ogl_config.bSupportsGLPinnedMemory ? ""
: "PinnedMemory ", g_ogl_config.bSupportsGLSLCache ? "" : "ShaderCache "
, g_ogl_config.bSupportsGLBaseVertex ? "" : "BaseVertex ", g_ogl_config
.bSupportsGLSync ? "" : "Sync ", g_ogl_config.bSupportCoverageMSAA
? "" : "CSAA ", g_ogl_config.bSupportSampleShading ? "" : "SSAA "
); } } while (0)
500 g_ogl_config.bSupportCoverageMSAA ? "" : "CSAA ",do { { if (LogTypes::LWARNING <= 3) GenericLog(LogTypes::LWARNING
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 502, "Missing OGL Extensions: %s%s%s%s%s%s%s%s%s", g_ActiveConfig
.backend_info.bSupportsDualSourceBlend ? "" : "DualSourceBlend "
, g_ActiveConfig.backend_info.bSupportsGLSLUBO ? "" : "UniformBuffer "
, g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? "" :
"PrimitiveRestart ", g_ogl_config.bSupportsGLPinnedMemory ? ""
: "PinnedMemory ", g_ogl_config.bSupportsGLSLCache ? "" : "ShaderCache "
, g_ogl_config.bSupportsGLBaseVertex ? "" : "BaseVertex ", g_ogl_config
.bSupportsGLSync ? "" : "Sync ", g_ogl_config.bSupportCoverageMSAA
? "" : "CSAA ", g_ogl_config.bSupportSampleShading ? "" : "SSAA "
); } } while (0)
501 g_ogl_config.bSupportSampleShading ? "" : "SSAA "do { { if (LogTypes::LWARNING <= 3) GenericLog(LogTypes::LWARNING
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 502, "Missing OGL Extensions: %s%s%s%s%s%s%s%s%s", g_ActiveConfig
.backend_info.bSupportsDualSourceBlend ? "" : "DualSourceBlend "
, g_ActiveConfig.backend_info.bSupportsGLSLUBO ? "" : "UniformBuffer "
, g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? "" :
"PrimitiveRestart ", g_ogl_config.bSupportsGLPinnedMemory ? ""
: "PinnedMemory ", g_ogl_config.bSupportsGLSLCache ? "" : "ShaderCache "
, g_ogl_config.bSupportsGLBaseVertex ? "" : "BaseVertex ", g_ogl_config
.bSupportsGLSync ? "" : "Sync ", g_ogl_config.bSupportCoverageMSAA
? "" : "CSAA ", g_ogl_config.bSupportSampleShading ? "" : "SSAA "
); } } while (0)
502 )do { { if (LogTypes::LWARNING <= 3) GenericLog(LogTypes::LWARNING
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 502, "Missing OGL Extensions: %s%s%s%s%s%s%s%s%s", g_ActiveConfig
.backend_info.bSupportsDualSourceBlend ? "" : "DualSourceBlend "
, g_ActiveConfig.backend_info.bSupportsGLSLUBO ? "" : "UniformBuffer "
, g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? "" :
"PrimitiveRestart ", g_ogl_config.bSupportsGLPinnedMemory ? ""
: "PinnedMemory ", g_ogl_config.bSupportsGLSLCache ? "" : "ShaderCache "
, g_ogl_config.bSupportsGLBaseVertex ? "" : "BaseVertex ", g_ogl_config
.bSupportsGLSync ? "" : "Sync ", g_ogl_config.bSupportCoverageMSAA
? "" : "CSAA ", g_ogl_config.bSupportSampleShading ? "" : "SSAA "
); } } while (0)
;
503
504 s_LastMultisampleMode = g_ActiveConfig.iMultisampleMode;
505 s_MSAASamples = GetNumMSAASamples(s_LastMultisampleMode);
506 s_MSAACoverageSamples = GetNumMSAACoverageSamples(s_LastMultisampleMode);
507 ApplySSAASettings();
508
509 // Decide framebuffer size
510 s_backbuffer_width = (int)GLInterface->GetBackBufferWidth();
511 s_backbuffer_height = (int)GLInterface->GetBackBufferHeight();
512
513 // Handle VSync on/off
514 s_vsync = g_ActiveConfig.IsVSync();
515 GLInterface->SwapInterval(s_vsync);
516
517 // check the max texture width and height
518 GLint max_texture_size;
519 glGetIntegerv(GL_MAX_TEXTURE_SIZE0x0D33, (GLint *)&max_texture_size);
520 if (max_texture_size < 1024)
521 ERROR_LOG(VIDEO, "GL_MAX_TEXTURE_SIZE too small at %i - must be at least 1024.",do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 522, "GL_MAX_TEXTURE_SIZE too small at %i - must be at least 1024."
, max_texture_size); } } while (0)
522 max_texture_size)do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 522, "GL_MAX_TEXTURE_SIZE too small at %i - must be at least 1024."
, max_texture_size); } } while (0)
;
523
524 if (GL_REPORT_ERROR() != GL_NO_ERROR0)
525 bSuccess = false;
526
527 // TODO: Move these somewhere else?
528 FramebufferManagerBase::SetLastXfbWidth(MAX_XFB_WIDTH);
529 FramebufferManagerBase::SetLastXfbHeight(MAX_XFB_HEIGHT);
530
531 UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height);
532
533 s_LastEFBScale = g_ActiveConfig.iEFBScale;
534 CalculateTargetSize(s_backbuffer_width, s_backbuffer_height);
535
536 // Because of the fixed framebuffer size we need to disable the resolution
537 // options while running
538 g_Config.bRunning = true;
539
540 if (GL_REPORT_ERROR() != GL_NO_ERROR0)
541 bSuccess = false;
542
543 // Initialize the FramebufferManager
544 g_framebuffer_manager = new FramebufferManager(s_target_width, s_target_height,
545 s_MSAASamples, s_MSAACoverageSamples);
546
547 if (GL_REPORT_ERROR() != GL_NO_ERROR0)
548 bSuccess = false;
549
550 glStencilFunc(GL_ALWAYS0x0207, 0, 0);
551 glBlendFunc(GL_ONE1, GL_ONE1);
552
553 glViewport(0, 0, GetTargetWidth(), GetTargetHeight()); // Reset The Current Viewport
554
555 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
556 glClearDepthf__glewClearDepthf(1.0f);
557 glEnable(GL_DEPTH_TEST0x0B71);
558 glDepthFunc(GL_LEQUAL0x0203);
559
560 glPixelStorei(GL_UNPACK_ALIGNMENT0x0CF5, 4); // 4-byte pixel alignment
561
562 glDisable(GL_STENCIL_TEST0x0B90);
563 glEnable(GL_SCISSOR_TEST0x0C11);
564
565 glScissor(0, 0, GetTargetWidth(), GetTargetHeight());
566 glBlendColor__glewBlendColor(0, 0, 0, 0.5f);
567 glClearDepthf__glewClearDepthf(1.0f);
568
569#ifndef USE_GLES3
570 if(g_ActiveConfig.backend_info.bSupportsPrimitiveRestart)
571 {
572 if(g_ogl_config.bSupportOGL31)
573 {
574 glEnable(GL_PRIMITIVE_RESTART0x8F9D);
575 glPrimitiveRestartIndex__glewPrimitiveRestartIndex(65535);
576 }
577 else
578 {
579 glEnableClientState(GL_PRIMITIVE_RESTART_NV0x8558);
580 glPrimitiveRestartIndexNV__glewPrimitiveRestartIndexNV(65535);
581 }
582 }
583#endif
584 UpdateActiveConfig();
585}
586
587Renderer::~Renderer()
588{
589
590#if defined(HAVE_WX1) && HAVE_WX1
591 if (scrshotThread.joinable())
592 scrshotThread.join();
593#endif
594
595 delete g_framebuffer_manager;
596}
597
598void Renderer::Shutdown()
599{
600 g_Config.bRunning = false;
601 UpdateActiveConfig();
602
603 glDeleteBuffers__glewDeleteBuffers(1, &s_ShowEFBCopyRegions_VBO);
604 glDeleteVertexArrays__glewDeleteVertexArrays(1, &s_ShowEFBCopyRegions_VAO);
605 s_ShowEFBCopyRegions_VBO = 0;
606
607 delete s_pfont;
608 s_pfont = 0;
609 s_ShowEFBCopyRegions.Destroy();
610}
611
612void Renderer::Init()
613{
614 s_pfont = new RasterFont();
615
616 ProgramShaderCache::CompileShader(s_ShowEFBCopyRegions,
617 "ATTRIN vec2 rawpos;\n"
618 "ATTRIN vec3 color0;\n"
619 "VARYOUT vec4 c;\n"
620 "void main(void) {\n"
621 " gl_Position = vec4(rawpos,0,1);\n"
622 " c = vec4(color0, 1.0);\n"
623 "}\n",
624 "VARYIN vec4 c;\n"
625 "COLOROUT(ocol0)\n"
626 "void main(void) {\n"
627 " ocol0 = c;\n"
628 "}\n");
629
630 // creating buffers
631 glGenBuffers__glewGenBuffers(1, &s_ShowEFBCopyRegions_VBO);
632 glGenVertexArrays__glewGenVertexArrays(1, &s_ShowEFBCopyRegions_VAO);
633 glBindBuffer__glewBindBuffer(GL_ARRAY_BUFFER0x8892, s_ShowEFBCopyRegions_VBO);
634 glBindVertexArray__glewBindVertexArray( s_ShowEFBCopyRegions_VAO );
635 glEnableVertexAttribArray__glewEnableVertexAttribArray(SHADER_POSITION_ATTRIB0);
636 glVertexAttribPointer__glewVertexAttribPointer(SHADER_POSITION_ATTRIB0, 2, GL_FLOAT0x1406, 0, sizeof(GLfloat)*5, NULL__null);
637 glEnableVertexAttribArray__glewEnableVertexAttribArray(SHADER_COLOR0_ATTRIB5);
638 glVertexAttribPointer__glewVertexAttribPointer(SHADER_COLOR0_ATTRIB5, 3, GL_FLOAT0x1406, 0, sizeof(GLfloat)*5, (GLfloat*)NULL__null+2);
639}
640
641// Create On-Screen-Messages
642void Renderer::DrawDebugInfo()
643{
644 // Reset viewport for drawing text
645 glViewport(0, 0, GLInterface->GetBackBufferWidth(), GLInterface->GetBackBufferHeight());
646 // Draw various messages on the screen, like FPS, statistics, etc.
647 char debugtext_buffer[8192];
648 char *p = debugtext_buffer;
649 p[0] = 0;
650
651 if (g_ActiveConfig.bShowFPS)
652 p+=sprintf(p, "FPS: %d\n", s_fps);
653
654 if (SConfig::GetInstance().m_ShowLag)
655 p+=sprintf(p, "Lag: %llu\n", Movie::g_currentLagCount);
656
657 if (g_ActiveConfig.bShowInputDisplay)
658 p+=sprintf(p, "%s", Movie::GetInputDisplay().c_str());
659
660 if (g_ActiveConfig.bShowEFBCopyRegions)
661 {
662 // Set Line Size
663 glLineWidth(3.0f);
664
665 // 2*Coords + 3*Color
666 glBindBuffer__glewBindBuffer(GL_ARRAY_BUFFER0x8892, s_ShowEFBCopyRegions_VBO);
667 glBufferData__glewBufferData(GL_ARRAY_BUFFER0x8892, stats.efb_regions.size() * sizeof(GLfloat) * (2+3)*2*6, NULL__null, GL_STREAM_DRAW0x88E0);
668 GLfloat *Vertices = (GLfloat*)glMapBuffer__glewMapBuffer(GL_ARRAY_BUFFER0x8892, GL_WRITE_ONLY0x88B9);
669
670 // Draw EFB copy regions rectangles
671 int a = 0;
672 GLfloat color[3] = {0.0f, 1.0f, 1.0f};
673
674 for (std::vector<EFBRectangle>::const_iterator it = stats.efb_regions.begin();
675 it != stats.efb_regions.end(); ++it)
676 {
677 GLfloat halfWidth = EFB_WIDTH / 2.0f;
678 GLfloat halfHeight = EFB_HEIGHT / 2.0f;
679 GLfloat x = (GLfloat) -1.0f + ((GLfloat)it->left / halfWidth);
680 GLfloat y = (GLfloat) 1.0f - ((GLfloat)it->top / halfHeight);
681 GLfloat x2 = (GLfloat) -1.0f + ((GLfloat)it->right / halfWidth);
682 GLfloat y2 = (GLfloat) 1.0f - ((GLfloat)it->bottom / halfHeight);
683
684 Vertices[a++] = x;
685 Vertices[a++] = y;
686 Vertices[a++] = color[0];
687 Vertices[a++] = color[1];
688 Vertices[a++] = color[2];
689
690 Vertices[a++] = x2;
691 Vertices[a++] = y;
692 Vertices[a++] = color[0];
693 Vertices[a++] = color[1];
694 Vertices[a++] = color[2];
695
696
697 Vertices[a++] = x2;
698 Vertices[a++] = y;
699 Vertices[a++] = color[0];
700 Vertices[a++] = color[1];
701 Vertices[a++] = color[2];
702
703 Vertices[a++] = x2;
704 Vertices[a++] = y2;
705 Vertices[a++] = color[0];
706 Vertices[a++] = color[1];
707 Vertices[a++] = color[2];
708
709
710 Vertices[a++] = x2;
711 Vertices[a++] = y2;
712 Vertices[a++] = color[0];
713 Vertices[a++] = color[1];
714 Vertices[a++] = color[2];
715
716 Vertices[a++] = x;
717 Vertices[a++] = y2;
718 Vertices[a++] = color[0];
719 Vertices[a++] = color[1];
720 Vertices[a++] = color[2];
721
722
723 Vertices[a++] = x;
724 Vertices[a++] = y2;
725 Vertices[a++] = color[0];
726 Vertices[a++] = color[1];
727 Vertices[a++] = color[2];
728
729 Vertices[a++] = x;
730 Vertices[a++] = y;
731 Vertices[a++] = color[0];
732 Vertices[a++] = color[1];
733 Vertices[a++] = color[2];
734
735
736 Vertices[a++] = x;
737 Vertices[a++] = y;
738 Vertices[a++] = color[0];
739 Vertices[a++] = color[1];
740 Vertices[a++] = color[2];
741
742 Vertices[a++] = x2;
743 Vertices[a++] = y2;
744 Vertices[a++] = color[0];
745 Vertices[a++] = color[1];
746 Vertices[a++] = color[2];
747
748
749 Vertices[a++] = x2;
750 Vertices[a++] = y;
751 Vertices[a++] = color[0];
752 Vertices[a++] = color[1];
753 Vertices[a++] = color[2];
754
755 Vertices[a++] = x;
756 Vertices[a++] = y2;
757 Vertices[a++] = color[0];
758 Vertices[a++] = color[1];
759 Vertices[a++] = color[2];
760
761 // TO DO: build something nicer here
762 GLfloat temp = color[0];
763 color[0] = color[1];
764 color[1] = color[2];
765 color[2] = temp;
766 }
767 glUnmapBuffer__glewUnmapBuffer(GL_ARRAY_BUFFER0x8892);
768
769 s_ShowEFBCopyRegions.Bind();
770 glBindVertexArray__glewBindVertexArray( s_ShowEFBCopyRegions_VAO );
771 glDrawArrays(GL_LINES0x0001, 0, stats.efb_regions.size() * 2*6);
772
773 // Restore Line Size
774 SetLineWidth();
775
776 // Clear stored regions
777 stats.efb_regions.clear();
778 }
779
780 if (g_ActiveConfig.bOverlayStats)
781 p = Statistics::ToString(p);
782
783 if (g_ActiveConfig.bOverlayProjStats)
784 p = Statistics::ToStringProj(p);
785
786 // Render a shadow, and then the text.
787 if (p != debugtext_buffer)
788 {
789 Renderer::RenderText(debugtext_buffer, 21, 21, 0xDD000000);
790 Renderer::RenderText(debugtext_buffer, 20, 20, 0xFF00FFFF);
791 }
792}
793
794void Renderer::RenderText(const char *text, int left, int top, u32 color)
795{
796 const int nBackbufferWidth = (int)GLInterface->GetBackBufferWidth();
797 const int nBackbufferHeight = (int)GLInterface->GetBackBufferHeight();
798
799 s_pfont->printMultilineText(text,
800 left * 2.0f / (float)nBackbufferWidth - 1,
801 1 - top * 2.0f / (float)nBackbufferHeight,
802 0, nBackbufferWidth, nBackbufferHeight, color);
803
804 GL_REPORT_ERRORD()(void)0;
805}
806
807TargetRectangle Renderer::ConvertEFBRectangle(const EFBRectangle& rc)
808{
809 TargetRectangle result;
810 result.left = EFBToScaledX(rc.left);
811 result.top = EFBToScaledY(EFB_HEIGHT - rc.top);
812 result.right = EFBToScaledX(rc.right);
813 result.bottom = EFBToScaledY(EFB_HEIGHT - rc.bottom);
814 return result;
815}
816
817// Function: This function handles the OpenGL glScissor() function
818// ----------------------------
819// Call browser: OpcodeDecoding.cpp ExecuteDisplayList > Decode() > LoadBPReg()
820// case 0x52 > SetScissorRect()
821// ----------------------------
822// bpmem.scissorTL.x, y = 342x342
823// bpmem.scissorBR.x, y = 981x821
824// Renderer::GetTargetHeight() = the fixed ini file setting
825// donkopunchstania - it appears scissorBR is the bottom right pixel inside the scissor box
826// therefore the width and height are (scissorBR + 1) - scissorTL
827void Renderer::SetScissorRect(const TargetRectangle& rc)
828{
829 glScissor(rc.left, rc.bottom, rc.GetWidth(), rc.GetHeight());
830}
831
832void Renderer::SetColorMask()
833{
834 // Only enable alpha channel if it's supported by the current EFB format
835 GLenum ColorMask = GL_FALSE0, AlphaMask = GL_FALSE0;
836 if (bpmem.alpha_test.TestResult() != AlphaTest::FAIL)
837 {
838 if (bpmem.blendmode.colorupdate)
839 ColorMask = GL_TRUE1;
840 if (bpmem.blendmode.alphaupdate && (bpmem.zcontrol.pixel_format == PIXELFMT_RGBA6_Z241))
841 AlphaMask = GL_TRUE1;
842 }
843 glColorMask(ColorMask, ColorMask, ColorMask, AlphaMask);
844}
845
846void ClearEFBCache()
847{
848 for (u32 i = 0; i < EFB_CACHE_WIDTH * EFB_CACHE_HEIGHT; ++i)
849 s_efbCacheValid[0][i] = false;
850
851 for (u32 i = 0; i < EFB_CACHE_WIDTH * EFB_CACHE_HEIGHT; ++i)
852 s_efbCacheValid[1][i] = false;
853}
854
855void Renderer::UpdateEFBCache(EFBAccessType type, u32 cacheRectIdx, const EFBRectangle& efbPixelRc, const TargetRectangle& targetPixelRc, const u32* data)
856{
857 u32 cacheType = (type == PEEK_Z ? 0 : 1);
858
859 if (!s_efbCache[cacheType][cacheRectIdx].size())
860 s_efbCache[cacheType][cacheRectIdx].resize(EFB_CACHE_RECT_SIZE * EFB_CACHE_RECT_SIZE);
861
862 u32 targetPixelRcWidth = targetPixelRc.right - targetPixelRc.left;
863 u32 efbPixelRcHeight = efbPixelRc.bottom - efbPixelRc.top;
864 u32 efbPixelRcWidth = efbPixelRc.right - efbPixelRc.left;
865
866 for (u32 yCache = 0; yCache < efbPixelRcHeight; ++yCache)
867 {
868 u32 yEFB = efbPixelRc.top + yCache;
869 u32 yPixel = (EFBToScaledY(EFB_HEIGHT - yEFB) + EFBToScaledY(EFB_HEIGHT - yEFB - 1)) / 2;
870 u32 yData = yPixel - targetPixelRc.bottom;
871
872 for (u32 xCache = 0; xCache < efbPixelRcWidth; ++xCache)
873 {
874 u32 xEFB = efbPixelRc.left + xCache;
875 u32 xPixel = (EFBToScaledX(xEFB) + EFBToScaledX(xEFB + 1)) / 2;
876 u32 xData = xPixel - targetPixelRc.left;
877 s_efbCache[cacheType][cacheRectIdx][yCache * EFB_CACHE_RECT_SIZE + xCache] = data[yData * targetPixelRcWidth + xData];
878 }
879 }
880
881 s_efbCacheValid[cacheType][cacheRectIdx] = true;
882}
883
884// This function allows the CPU to directly access the EFB.
885// There are EFB peeks (which will read the color or depth of a pixel)
886// and EFB pokes (which will change the color or depth of a pixel).
887//
888// The behavior of EFB peeks can only be modified by:
889// - GX_PokeAlphaRead
890// The behavior of EFB pokes can be modified by:
891// - GX_PokeAlphaMode (TODO)
892// - GX_PokeAlphaUpdate (TODO)
893// - GX_PokeBlendMode (TODO)
894// - GX_PokeColorUpdate (TODO)
895// - GX_PokeDither (TODO)
896// - GX_PokeDstAlpha (TODO)
897// - GX_PokeZMode (TODO)
898u32 Renderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data)
899{
900 if (!g_ActiveConfig.bEFBAccessEnable)
901 return 0;
902
903 u32 cacheRectIdx = (y / EFB_CACHE_RECT_SIZE) * EFB_CACHE_WIDTH
904 + (x / EFB_CACHE_RECT_SIZE);
905
906 // Get the rectangular target region containing the EFB pixel
907 EFBRectangle efbPixelRc;
908 efbPixelRc.left = (x / EFB_CACHE_RECT_SIZE) * EFB_CACHE_RECT_SIZE;
909 efbPixelRc.top = (y / EFB_CACHE_RECT_SIZE) * EFB_CACHE_RECT_SIZE;
910 efbPixelRc.right = std::min(efbPixelRc.left + EFB_CACHE_RECT_SIZE, (u32)EFB_WIDTH);
911 efbPixelRc.bottom = std::min(efbPixelRc.top + EFB_CACHE_RECT_SIZE, (u32)EFB_HEIGHT);
912
913 TargetRectangle targetPixelRc = ConvertEFBRectangle(efbPixelRc);
914 u32 targetPixelRcWidth = targetPixelRc.right - targetPixelRc.left;
915 u32 targetPixelRcHeight = targetPixelRc.top - targetPixelRc.bottom;
916
917 // TODO (FIX) : currently, AA path is broken/offset and doesn't return the correct pixel
918 switch (type)
919 {
920 case PEEK_Z:
921 {
922 u32 z;
923
924 if (!s_efbCacheValid[0][cacheRectIdx])
925 {
926 if (s_MSAASamples > 1)
927 {
928 // Resolve our rectangle.
929 FramebufferManager::GetEFBDepthTexture(efbPixelRc);
930 glBindFramebuffer__glewBindFramebuffer(GL_READ_FRAMEBUFFER0x8CA8, FramebufferManager::GetResolvedFramebuffer());
931 }
932
933 u32* depthMap = new u32[targetPixelRcWidth * targetPixelRcHeight];
934
935 glReadPixels(targetPixelRc.left, targetPixelRc.bottom, targetPixelRcWidth, targetPixelRcHeight,
936 GL_DEPTH_COMPONENT0x1902, GL_UNSIGNED_INT0x1405, depthMap);
937 GL_REPORT_ERRORD()(void)0;
938
939 UpdateEFBCache(type, cacheRectIdx, efbPixelRc, targetPixelRc, depthMap);
940
941 delete[] depthMap;
942 }
943
944 u32 xRect = x % EFB_CACHE_RECT_SIZE;
945 u32 yRect = y % EFB_CACHE_RECT_SIZE;
946 z = s_efbCache[0][cacheRectIdx][yRect * EFB_CACHE_RECT_SIZE + xRect];
947
948 // Scale the 32-bit value returned by glReadPixels to a 24-bit
949 // value (GC uses a 24-bit Z-buffer).
950 // TODO: in RE0 this value is often off by one, which causes lighting to disappear
951 if(bpmem.zcontrol.pixel_format == PIXELFMT_RGB565_Z162)
952 {
953 // if Z is in 16 bit format you must return a 16 bit integer
954 z = z >> 16;
955 }
956 else
957 {
958 z = z >> 8;
959 }
960 return z;
961 }
962
963 case PEEK_COLOR: // GXPeekARGB
964 {
965 // Although it may sound strange, this really is A8R8G8B8 and not RGBA or 24-bit...
966
967 // Tested in Killer 7, the first 8bits represent the alpha value which is used to
968 // determine if we're aiming at an enemy (0x80 / 0x88) or not (0x70)
969 // Wind Waker is also using it for the pictograph to determine the color of each pixel
970
971 u32 color;
972
973 if (!s_efbCacheValid[1][cacheRectIdx])
974 {
975 if (s_MSAASamples > 1)
976 {
977 // Resolve our rectangle.
978 FramebufferManager::GetEFBColorTexture(efbPixelRc);
979 glBindFramebuffer__glewBindFramebuffer(GL_READ_FRAMEBUFFER0x8CA8, FramebufferManager::GetResolvedFramebuffer());
980 }
981
982 u32* colorMap = new u32[targetPixelRcWidth * targetPixelRcHeight];
983
984#ifdef USE_GLES3
985 // XXX: Swap colours
986 glReadPixels(targetPixelRc.left, targetPixelRc.bottom, targetPixelRcWidth, targetPixelRcHeight,
987 GL_RGBA0x1908, GL_UNSIGNED_BYTE0x1401, colorMap);
988#else
989 glReadPixels(targetPixelRc.left, targetPixelRc.bottom, targetPixelRcWidth, targetPixelRcHeight,
990 GL_BGRA0x80E1, GL_UNSIGNED_INT_8_8_8_8_REV0x8367, colorMap);
991#endif
992 GL_REPORT_ERRORD()(void)0;
993
994 UpdateEFBCache(type, cacheRectIdx, efbPixelRc, targetPixelRc, colorMap);
995
996 delete[] colorMap;
997 }
998
999 u32 xRect = x % EFB_CACHE_RECT_SIZE;
1000 u32 yRect = y % EFB_CACHE_RECT_SIZE;
1001 color = s_efbCache[1][cacheRectIdx][yRect * EFB_CACHE_RECT_SIZE + xRect];
1002
1003 // check what to do with the alpha channel (GX_PokeAlphaRead)
1004 PixelEngine::UPEAlphaReadReg alpha_read_mode;
1005 PixelEngine::Read16((u16&)alpha_read_mode, PE_ALPHAREAD);
1006
1007 if (bpmem.zcontrol.pixel_format == PIXELFMT_RGBA6_Z241)
1008 {
1009 color = RGBA8ToRGBA6ToRGBA8(color);
1010 }
1011 else if (bpmem.zcontrol.pixel_format == PIXELFMT_RGB565_Z162)
1012 {
1013 color = RGBA8ToRGB565ToRGBA8(color);
1014 }
1015 if(bpmem.zcontrol.pixel_format != PIXELFMT_RGBA6_Z241)
1016 {
1017 color |= 0xFF000000;
1018 }
1019 if(alpha_read_mode.ReadMode == 2) return color; // GX_READ_NONE
1020 else if(alpha_read_mode.ReadMode == 1) return (color | 0xFF000000); // GX_READ_FF
1021 else /*if(alpha_read_mode.ReadMode == 0)*/ return (color & 0x00FFFFFF); // GX_READ_00
1022 }
1023
1024 case POKE_COLOR:
1025 case POKE_Z:
1026 // TODO: Implement. One way is to draw a tiny pixel-sized rectangle at
1027 // the exact location. Note: EFB pokes are susceptible to Z-buffering
1028 // and perhaps blending.
1029 //WARN_LOG(VIDEOINTERFACE, "This is probably some kind of software rendering");
1030 break;
1031
1032 default:
1033 break;
1034 }
1035
1036 return 0;
1037}
1038
1039// Called from VertexShaderManager
1040void Renderer::UpdateViewport(Matrix44& vpCorrection)
1041{
1042 // reversed gxsetviewport(xorig, yorig, width, height, nearz, farz)
1043 // [0] = width/2
1044 // [1] = height/2
1045 // [2] = 16777215 * (farz - nearz)
1046 // [3] = xorig + width/2 + 342
1047 // [4] = yorig + height/2 + 342
1048 // [5] = 16777215 * farz
1049
1050 int scissorXOff = bpmem.scissorOffset.x * 2;
1051 int scissorYOff = bpmem.scissorOffset.y * 2;
1052
1053 // TODO: ceil, floor or just cast to int?
1054 int X = EFBToScaledX((int)ceil(xfregs.viewport.xOrig - xfregs.viewport.wd - (float)scissorXOff));
1055 int Y = EFBToScaledY((int)ceil((float)EFB_HEIGHT - xfregs.viewport.yOrig + xfregs.viewport.ht + (float)scissorYOff));
1056 int Width = EFBToScaledX((int)ceil(2.0f * xfregs.viewport.wd));
1057 int Height = EFBToScaledY((int)ceil(-2.0f * xfregs.viewport.ht));
1058 double GLNear = (xfregs.viewport.farZ - xfregs.viewport.zRange) / 16777216.0f;
1059 double GLFar = xfregs.viewport.farZ / 16777216.0f;
1060 if (Width < 0)
1061 {
1062 X += Width;
1063 Width *= -1;
1064 }
1065 if (Height < 0)
1066 {
1067 Y += Height;
1068 Height *= -1;
1069 }
1070
1071 // OpenGL does not require any viewport correct
1072 Matrix44::LoadIdentity(vpCorrection);
1073
1074 // Update the view port
1075 glViewport(X, Y, Width, Height);
1076 glDepthRangef__glewDepthRangef(GLNear, GLFar);
1077}
1078
1079void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z)
1080{
1081 ResetAPIState();
1082
1083 // color
1084 GLboolean const
1085 color_mask = colorEnable ? GL_TRUE1 : GL_FALSE0,
1086 alpha_mask = alphaEnable ? GL_TRUE1 : GL_FALSE0;
1087 glColorMask(color_mask, color_mask, color_mask, alpha_mask);
1088
1089 glClearColor(
1090 float((color >> 16) & 0xFF) / 255.0f,
1091 float((color >> 8) & 0xFF) / 255.0f,
1092 float((color >> 0) & 0xFF) / 255.0f,
1093 float((color >> 24) & 0xFF) / 255.0f);
1094
1095 // depth
1096 glDepthMask(zEnable ? GL_TRUE1 : GL_FALSE0);
1097
1098 glClearDepthf__glewClearDepthf(float(z & 0xFFFFFF) / float(0xFFFFFF));
1099
1100 // Update rect for clearing the picture
1101 glEnable(GL_SCISSOR_TEST0x0C11);
1102
1103 TargetRectangle const targetRc = ConvertEFBRectangle(rc);
1104 glScissor(targetRc.left, targetRc.bottom, targetRc.GetWidth(), targetRc.GetHeight());
1105
1106 // glColorMask/glDepthMask/glScissor affect glClear (glViewport does not)
1107 glClear(GL_COLOR_BUFFER_BIT0x00004000 | GL_DEPTH_BUFFER_BIT0x00000100);
1108
1109 RestoreAPIState();
1110
1111 ClearEFBCache();
1112}
1113
1114void Renderer::ReinterpretPixelData(unsigned int convtype)
1115{
1116 // TODO
1117}
1118
1119void Renderer::SetBlendMode(bool forceUpdate)
1120{
1121 // Our render target always uses an alpha channel, so we need to override the blend functions to assume a destination alpha of 1 if the render target isn't supposed to have an alpha channel
1122 // Example: D3DBLEND_DESTALPHA needs to be D3DBLEND_ONE since the result without an alpha channel is assumed to always be 1.
1123 bool target_has_alpha = bpmem.zcontrol.pixel_format == PIXELFMT_RGBA6_Z241;
1124
1125 bool useDstAlpha = !g_ActiveConfig.bDstAlphaPass && bpmem.dstalpha.enable && bpmem.blendmode.alphaupdate && target_has_alpha;
1126 bool useDualSource = useDstAlpha && g_ActiveConfig.backend_info.bSupportsDualSourceBlend;
1127
1128 const GLenum glSrcFactors[8] =
1129 {
1130 GL_ZERO0,
1131 GL_ONE1,
1132 GL_DST_COLOR0x0306,
1133 GL_ONE_MINUS_DST_COLOR0x0307,
1134 (useDualSource) ? GL_SRC1_ALPHA0x8589 : (GLenum)GL_SRC_ALPHA0x0302,
1135 (useDualSource) ? GL_ONE_MINUS_SRC1_ALPHA0x88FB : (GLenum)GL_ONE_MINUS_SRC_ALPHA0x0303,
1136 (target_has_alpha) ? GL_DST_ALPHA0x0304 : (GLenum)GL_ONE1,
1137 (target_has_alpha) ? GL_ONE_MINUS_DST_ALPHA0x0305 : (GLenum)GL_ZERO0
1138 };
1139 const GLenum glDestFactors[8] =
1140 {
1141 GL_ZERO0,
1142 GL_ONE1,
1143 GL_SRC_COLOR0x0300,
1144 GL_ONE_MINUS_SRC_COLOR0x0301,
1145 (useDualSource) ? GL_SRC1_ALPHA0x8589 : (GLenum)GL_SRC_ALPHA0x0302,
1146 (useDualSource) ? GL_ONE_MINUS_SRC1_ALPHA0x88FB : (GLenum)GL_ONE_MINUS_SRC_ALPHA0x0303,
1147 (target_has_alpha) ? GL_DST_ALPHA0x0304 : (GLenum)GL_ONE1,
1148 (target_has_alpha) ? GL_ONE_MINUS_DST_ALPHA0x0305 : (GLenum)GL_ZERO0
1149 };
1150
1151 // blend mode bit mask
1152 // 0 - blend enable
1153 // 1 - dst alpha enabled
1154 // 2 - reverse subtract enable (else add)
1155 // 3-5 - srcRGB function
1156 // 6-8 - dstRGB function
1157
1158 u32 newval = useDualSource << 1;
1159 newval |= bpmem.blendmode.subtract << 2;
1160
1161 if (bpmem.blendmode.subtract)
1162 newval |= 0x0049; // enable blending src 1 dst 1
1163 else if (bpmem.blendmode.blendenable)
1164 {
1165 newval |= 1; // enable blending
1166 newval |= bpmem.blendmode.srcfactor << 3;
1167 newval |= bpmem.blendmode.dstfactor << 6;
1168 }
1169
1170 u32 changes = forceUpdate ? 0xFFFFFFFF : newval ^ s_blendMode;
1171
1172 if (changes & 1)
1173 // blend enable change
1174 (newval & 1) ? glEnable(GL_BLEND0x0BE2) : glDisable(GL_BLEND0x0BE2);
1175
1176 if (changes & 4)
1177 {
1178 // subtract enable change
1179 GLenum equation = newval & 4 ? GL_FUNC_REVERSE_SUBTRACT0x800B : GL_FUNC_ADD0x8006;
1180 GLenum equationAlpha = useDualSource ? GL_FUNC_ADD0x8006 : equation;
1181
1182 glBlendEquationSeparate__glewBlendEquationSeparate(equation, equationAlpha);
1183 }
1184
1185 if (changes & 0x1FA)
1186 {
1187 u32 srcidx = (newval >> 3) & 7;
1188 u32 dstidx = (newval >> 6) & 7;
1189 GLenum srcFactor = glSrcFactors[srcidx];
1190 GLenum dstFactor = glDestFactors[dstidx];
1191
1192 // adjust alpha factors
1193 if (useDualSource)
1194 {
1195 srcidx = GX_BL_ONE1;
1196 dstidx = GX_BL_ZERO0;
1197 }
1198 else
1199 {
1200 // we can't use GL_DST_COLOR or GL_ONE_MINUS_DST_COLOR for source in alpha channel so use their alpha equivalent instead
1201 if (srcidx == GX_BL_DSTCLR2) srcidx = GX_BL_DSTALPHA6;
1202 if (srcidx == GX_BL_INVDSTCLR3) srcidx = GX_BL_INVDSTALPHA7;
1203
1204 // we can't use GL_SRC_COLOR or GL_ONE_MINUS_SRC_COLOR for destination in alpha channel so use their alpha equivalent instead
1205 if (dstidx == GX_BL_SRCCLR2) dstidx = GX_BL_SRCALPHA4;
1206 if (dstidx == GX_BL_INVSRCCLR3) dstidx = GX_BL_INVSRCALPHA5;
1207 }
1208 GLenum srcFactorAlpha = glSrcFactors[srcidx];
1209 GLenum dstFactorAlpha = glDestFactors[dstidx];
1210 // blend RGB change
1211 glBlendFuncSeparate__glewBlendFuncSeparate(srcFactor, dstFactor, srcFactorAlpha, dstFactorAlpha);
1212 }
1213 s_blendMode = newval;
1214}
1215
1216void DumpFrame(const std::vector<u8>& data, int w, int h)
1217{
1218#if defined(HAVE_LIBAV) || defined(_WIN32)
1219 if (g_ActiveConfig.bDumpFrames && !data.empty())
1220 {
1221 AVIDump::AddFrame(&data[0], w, h);
1222 }
1223#endif
1224}
1225
1226// This function has the final picture. We adjust the aspect ratio here.
1227void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,const EFBRectangle& rc,float Gamma)
1228{
1229 static int w = 0, h = 0;
1230 if (g_bSkipCurrentFrame || (!XFBWrited && !g_ActiveConfig.RealXFBEnabled()) || !fbWidth || !fbHeight)
1231 {
1232 DumpFrame(frame_data, w, h);
1233 Core::Callback_VideoCopiedToXFB(false);
1234 return;
1235 }
1236
1237 if (field == FIELD_LOWER) xfbAddr -= fbWidth * 2;
1238 u32 xfbCount = 0;
1239 const XFBSourceBase* const* xfbSourceList = FramebufferManager::GetXFBSource(xfbAddr, fbWidth, fbHeight, xfbCount);
1240 if (g_ActiveConfig.VirtualXFBEnabled() && (!xfbSourceList || xfbCount == 0))
1241 {
1242 DumpFrame(frame_data, w, h);
1243 Core::Callback_VideoCopiedToXFB(false);
1244 return;
1245 }
1246
1247 ResetAPIState();
1248
1249 PostProcessing::Update(s_backbuffer_width, s_backbuffer_height);
1250 UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height);
1251 TargetRectangle flipped_trc = GetTargetRectangle();
1252
1253 // Flip top and bottom for some reason; TODO: Fix the code to suck less?
1254 int tmp = flipped_trc.top;
1255 flipped_trc.top = flipped_trc.bottom;
1256 flipped_trc.bottom = tmp;
1257
1258 GL_REPORT_ERRORD()(void)0;
1259
1260 // Copy the framebuffer to screen.
1261
1262 const XFBSourceBase* xfbSource = NULL__null;
1263
1264 if(g_ActiveConfig.bUseXFB)
1265 {
1266 // Render to the real/postprocessing buffer now.
1267 PostProcessing::BindTargetFramebuffer();
1268
1269 // draw each xfb source
1270 glBindFramebuffer__glewBindFramebuffer(GL_READ_FRAMEBUFFER0x8CA8, FramebufferManager::GetXFBFramebuffer());
1271
1272 for (u32 i = 0; i < xfbCount; ++i)
1273 {
1274 xfbSource = xfbSourceList[i];
1275
1276 MathUtil::Rectangle<float> drawRc;
1277
1278 if (g_ActiveConfig.bUseRealXFB)
1279 {
1280 drawRc.top = flipped_trc.top;
1281 drawRc.bottom = flipped_trc.bottom;
1282 drawRc.left = flipped_trc.left;
1283 drawRc.right = flipped_trc.right;
1284 }
1285 else
1286 {
1287 // use virtual xfb with offset
1288 int xfbHeight = xfbSource->srcHeight;
1289 int xfbWidth = xfbSource->srcWidth;
1290 int hOffset = ((s32)xfbSource->srcAddr - (s32)xfbAddr) / ((s32)fbWidth * 2);
1291
1292 drawRc.top = flipped_trc.top - hOffset * flipped_trc.GetHeight() / fbHeight;
1293 drawRc.bottom = flipped_trc.top - (hOffset + xfbHeight) * flipped_trc.GetHeight() / fbHeight;
1294 drawRc.left = flipped_trc.left + (flipped_trc.GetWidth() - xfbWidth * flipped_trc.GetWidth() / fbWidth)/2;
1295 drawRc.right = flipped_trc.left + (flipped_trc.GetWidth() + xfbWidth * flipped_trc.GetWidth() / fbWidth)/2;
1296
1297 // The following code disables auto stretch. Kept for reference.
1298 // scale draw area for a 1 to 1 pixel mapping with the draw target
1299 //float vScale = (float)fbHeight / (float)flipped_trc.GetHeight();
1300 //float hScale = (float)fbWidth / (float)flipped_trc.GetWidth();
1301 //drawRc.top *= vScale;
1302 //drawRc.bottom *= vScale;
1303 //drawRc.left *= hScale;
1304 //drawRc.right *= hScale;
1305 }
1306 // Tell the OSD Menu about the current internal resolution
1307 OSDInternalW = xfbSource->sourceRc.GetWidth(); OSDInternalH = xfbSource->sourceRc.GetHeight();
1308
1309 MathUtil::Rectangle<float> sourceRc;
1310 sourceRc.left = xfbSource->sourceRc.left;
1311 sourceRc.right = xfbSource->sourceRc.right;
1312 sourceRc.top = xfbSource->sourceRc.top;
1313 sourceRc.bottom = xfbSource->sourceRc.bottom;
1314
1315 xfbSource->Draw(sourceRc, drawRc, 0, 0);
1316 }
1317 }
1318 else
1319 {
1320 TargetRectangle targetRc = ConvertEFBRectangle(rc);
1321
1322 // for msaa mode, we must resolve the efb content to non-msaa
1323 FramebufferManager::ResolveAndGetRenderTarget(rc);
1324
1325 // Render to the real/postprocessing buffer now. (resolve have changed this in msaa mode)
1326 PostProcessing::BindTargetFramebuffer();
1327
1328 // always the non-msaa fbo
1329 GLuint fb = s_MSAASamples>1?FramebufferManager::GetResolvedFramebuffer():FramebufferManager::GetEFBFramebuffer();
1330
1331 glBindFramebuffer__glewBindFramebuffer(GL_READ_FRAMEBUFFER0x8CA8, fb);
1332 glBlitFramebuffer__glewBlitFramebuffer(targetRc.left, targetRc.bottom, targetRc.right, targetRc.top,
1333 flipped_trc.left, flipped_trc.bottom, flipped_trc.right, flipped_trc.top,
1334 GL_COLOR_BUFFER_BIT0x00004000, GL_LINEAR0x2601);
1335 }
1336
1337 PostProcessing::BlitToScreen();
1338
1339 glBindFramebuffer__glewBindFramebuffer(GL_READ_FRAMEBUFFER0x8CA8, 0);
1340
1341 // Save screenshot
1342 if (s_bScreenshot)
1343 {
1344 std::lock_guard<std::mutex> lk(s_criticalScreenshot);
1345 SaveScreenshot(s_sScreenshotName, flipped_trc);
1346 // Reset settings
1347 s_sScreenshotName.clear();
1348 s_bScreenshot = false;
1349 }
1350
1351 // Frame dumps are handled a little differently in Windows
1352 // Frame dumping disabled entirely on GLES3
1353#ifndef USE_GLES3
1354#if defined _WIN32 || defined HAVE_LIBAV
1355 if (g_ActiveConfig.bDumpFrames)
1356 {
1357 std::lock_guard<std::mutex> lk(s_criticalScreenshot);
1358 if (frame_data.empty() || w != flipped_trc.GetWidth() ||
1359 h != flipped_trc.GetHeight())
1360 {
1361 w = flipped_trc.GetWidth();
1362 h = flipped_trc.GetHeight();
1363 frame_data.resize(3 * w * h);
1364 }
1365 glPixelStorei(GL_PACK_ALIGNMENT0x0D05, 1);
1366 glReadPixels(flipped_trc.left, flipped_trc.bottom, w, h, GL_BGR0x80E0, GL_UNSIGNED_BYTE0x1401, &frame_data[0]);
1367 if (GL_REPORT_ERROR() == GL_NO_ERROR0 && w > 0 && h > 0)
1368 {
1369 if (!bLastFrameDumped)
1370 {
1371 #ifdef _WIN32
1372 bAVIDumping = AVIDump::Start(EmuWindow::GetParentWnd(), w, h);
1373 #else
1374 bAVIDumping = AVIDump::Start(w, h);
1375 #endif
1376 if (!bAVIDumping)
1377 OSD::AddMessage("AVIDump Start failed", 2000);
1378 else
1379 {
1380 OSD::AddMessage(StringFromFormat(
1381 "Dumping Frames to \"%sframedump0.avi\" (%dx%d RGB24)",
1382 File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), w, h).c_str(), 2000);
1383 }
1384 }
1385 if (bAVIDumping)
1386 {
1387 #ifndef _WIN32
1388 FlipImageData(&frame_data[0], w, h);
1389 #endif
1390
1391 AVIDump::AddFrame(&frame_data[0], w, h);
1392 }
1393
1394 bLastFrameDumped = true;
1395 }
1396 else
1397 NOTICE_LOG(VIDEO, "Error reading framebuffer")do { { if (LogTypes::LNOTICE <= 3) GenericLog(LogTypes::LNOTICE
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 1397, "Error reading framebuffer"); } } while (0)
;
1398 }
1399 else
1400 {
1401 if (bLastFrameDumped && bAVIDumping)
1402 {
1403 std::vector<u8>().swap(frame_data);
1404 w = h = 0;
1405 AVIDump::Stop();
1406 bAVIDumping = false;
1407 OSD::AddMessage("Stop dumping frames", 2000);
1408 }
1409 bLastFrameDumped = false;
1410 }
1411#else
1412 if (g_ActiveConfig.bDumpFrames)
1413 {
1414 std::lock_guard<std::mutex> lk(s_criticalScreenshot);
1415 std::string movie_file_name;
1416 w = GetTargetRectangle().GetWidth();
1417 h = GetTargetRectangle().GetHeight();
1418 frame_data.resize(3 * w * h);
1419 glPixelStorei(GL_PACK_ALIGNMENT0x0D05, 1);
1420 glReadPixels(GetTargetRectangle().left, GetTargetRectangle().bottom, w, h, GL_BGR0x80E0, GL_UNSIGNED_BYTE0x1401, &frame_data[0]);
1421 if (GL_REPORT_ERROR() == GL_NO_ERROR0)
1422 {
1423 if (!bLastFrameDumped)
1424 {
1425 movie_file_name = File::GetUserPath(D_DUMPFRAMES_IDX) + "framedump.raw";
1426 pFrameDump.Open(movie_file_name, "wb");
1427 if (!pFrameDump)
1428 OSD::AddMessage("Error opening framedump.raw for writing.", 2000);
1429 else
1430 {
1431 OSD::AddMessage(StringFromFormat("Dumping Frames to \"%s\" (%dx%d RGB24)", movie_file_name.c_str(), w, h).c_str(), 2000);
1432 }
1433 }
1434 if (pFrameDump)
1435 {
1436 FlipImageData(&frame_data[0], w, h);
1437 pFrameDump.WriteBytes(&frame_data[0], w * 3 * h);
1438 pFrameDump.Flush();
1439 }
1440 bLastFrameDumped = true;
1441 }
1442 }
1443 else
1444 {
1445 if (bLastFrameDumped)
1446 pFrameDump.Close();
1447 bLastFrameDumped = false;
1448 }
1449#endif
1450#endif
1451 // Finish up the current frame, print some stats
1452
1453 SetWindowSize(fbWidth, fbHeight);
1454
1455 GLInterface->Update(); // just updates the render window position and the backbuffer size
1456
1457 bool xfbchanged = false;
1458
1459 if (FramebufferManagerBase::LastXfbWidth() != fbWidth || FramebufferManagerBase::LastXfbHeight() != fbHeight)
1460 {
1461 xfbchanged = true;
1462 unsigned int const last_w = (fbWidth < 1 || fbWidth > MAX_XFB_WIDTH) ? MAX_XFB_WIDTH : fbWidth;
1463 unsigned int const last_h = (fbHeight < 1 || fbHeight > MAX_XFB_HEIGHT) ? MAX_XFB_HEIGHT : fbHeight;
1464 FramebufferManagerBase::SetLastXfbWidth(last_w);
1465 FramebufferManagerBase::SetLastXfbHeight(last_h);
1466 }
1467
1468 bool WindowResized = false;
1469 int W = (int)GLInterface->GetBackBufferWidth();
1470 int H = (int)GLInterface->GetBackBufferHeight();
1471 if (W != s_backbuffer_width || H != s_backbuffer_height || s_LastEFBScale != g_ActiveConfig.iEFBScale)
1472 {
1473 WindowResized = true;
1474 s_backbuffer_width = W;
1475 s_backbuffer_height = H;
1476 s_LastEFBScale = g_ActiveConfig.iEFBScale;
1477 }
1478
1479 if (xfbchanged || WindowResized || (s_LastMultisampleMode != g_ActiveConfig.iMultisampleMode))
1480 {
1481 UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height);
1482
1483 if (CalculateTargetSize(s_backbuffer_width, s_backbuffer_height) || s_LastMultisampleMode != g_ActiveConfig.iMultisampleMode)
1484 {
1485 s_LastMultisampleMode = g_ActiveConfig.iMultisampleMode;
1486 s_MSAASamples = GetNumMSAASamples(s_LastMultisampleMode);
1487 s_MSAACoverageSamples = GetNumMSAACoverageSamples(s_LastMultisampleMode);
1488 ApplySSAASettings();
1489
1490 delete g_framebuffer_manager;
1491 g_framebuffer_manager = new FramebufferManager(s_target_width, s_target_height,
1492 s_MSAASamples, s_MSAACoverageSamples);
1493 }
1494 }
1495
1496 if (XFBWrited)
1497 s_fps = UpdateFPSCounter();
1498 // ---------------------------------------------------------------------
1499 GL_REPORT_ERRORD()(void)0;
1500
1501 glEnable(GL_BLEND0x0BE2);
1502 glBlendFunc(GL_SRC_ALPHA0x0302, GL_ONE_MINUS_SRC_ALPHA0x0303);
1503
1504 DrawDebugInfo();
1505 DrawDebugText();
1506
1507 GL_REPORT_ERRORD()(void)0;
1508
1509 // Do our OSD callbacks
1510 OSD::DoCallbacks(OSD::OSD_ONFRAME);
1511 OSD::DrawMessages();
1512 GL_REPORT_ERRORD()(void)0;
1513
1514 // Copy the rendered frame to the real window
1515 GLInterface->Swap();
1516
1517 GL_REPORT_ERRORD()(void)0;
1518
1519 // Clear framebuffer
1520 if(!g_ActiveConfig.bAnaglyphStereo)
1521 {
1522 glClearColor(0, 0, 0, 0);
1523 glClear(GL_COLOR_BUFFER_BIT0x00004000);
1524 }
1525
1526 GL_REPORT_ERRORD()(void)0;
1527
1528 if(s_vsync != g_ActiveConfig.IsVSync())
1529 {
1530 s_vsync = g_ActiveConfig.IsVSync();
1531 GLInterface->SwapInterval(s_vsync);
1532 }
1533
1534 // Clean out old stuff from caches. It's not worth it to clean out the shader caches.
1535 DLCache::ProgressiveCleanup();
1536 TextureCache::Cleanup();
1537
1538 frameCount++;
1539
1540 GFX_DEBUGGER_PAUSE_AT(NEXT_FRAME, true){if (((GFXDebuggerToPauseAtNext & NEXT_FRAME) && --
GFXDebuggerEventToPauseCount<=0) || GFXDebuggerPauseFlag) GFXDebuggerToPause
(true);}
;
1541
1542 // Begin new frame
1543 // Set default viewport and scissor, for the clear to work correctly
1544 // New frame
1545 stats.ResetFrame();
1546
1547 // Render to the framebuffer.
1548 FramebufferManager::SetFramebuffer(0);
1549
1550 GL_REPORT_ERRORD()(void)0;
1551
1552 RestoreAPIState();
1553
1554 GL_REPORT_ERRORD()(void)0;
1555 g_Config.iSaveTargetId = 0;
1556
1557 UpdateActiveConfig();
1558 TextureCache::OnConfigChanged(g_ActiveConfig);
1559
1560 // For testing zbuffer targets.
1561 // Renderer::SetZBufferRender();
1562 // SaveTexture("tex.tga", GL_TEXTURE_2D, s_FakeZTarget,
1563 // GetTargetWidth(), GetTargetHeight());
1564 Core::Callback_VideoCopiedToXFB(XFBWrited || (g_ActiveConfig.bUseXFB && g_ActiveConfig.bUseRealXFB));
1565 XFBWrited = false;
1566
1567 // Invalidate EFB cache
1568 ClearEFBCache();
1569}
1570
1571// ALWAYS call RestoreAPIState for each ResetAPIState call you're doing
1572void Renderer::ResetAPIState()
1573{
1574 // Gets us to a reasonably sane state where it's possible to do things like
1575 // image copies with textured quads, etc.
1576 glDisable(GL_SCISSOR_TEST0x0C11);
1577 glDisable(GL_DEPTH_TEST0x0B71);
1578 glDisable(GL_CULL_FACE0x0B44);
1579 glDisable(GL_BLEND0x0BE2);
1580 glDepthMask(GL_FALSE0);
1581 glColorMask(GL_TRUE1, GL_TRUE1, GL_TRUE1, GL_TRUE1);
1582}
1583
1584void Renderer::RestoreAPIState()
1585{
1586 // Gets us back into a more game-like state.
1587 glEnable(GL_SCISSOR_TEST0x0C11);
1588 SetGenerationMode();
1589 BPFunctions::SetScissor();
1590 SetColorMask();
1591 SetDepthMode();
1592 SetBlendMode(true);
1593 VertexShaderManager::SetViewportChanged();
1594
1595#ifndef USE_GLES3
1596 glPolygonMode(GL_FRONT_AND_BACK0x0408, g_ActiveConfig.bWireFrame ? GL_LINE0x1B01 : GL_FILL0x1B02);
1597#endif
1598
1599 VertexManager *vm = (OGL::VertexManager*)g_vertex_manager;
1600 glBindBuffer__glewBindBuffer(GL_ARRAY_BUFFER0x8892, vm->m_vertex_buffers);
1601 vm->m_last_vao = 0;
1602
1603 TextureCache::SetStage();
1604}
1605
1606void Renderer::SetGenerationMode()
1607{
1608 // none, ccw, cw, ccw
1609 if (bpmem.genMode.cullmode > 0)
1610 {
1611 glEnable(GL_CULL_FACE0x0B44);
1612 glFrontFace(bpmem.genMode.cullmode == 2 ? GL_CCW0x0901 : GL_CW0x0900);
1613 }
1614 else
1615 glDisable(GL_CULL_FACE0x0B44);
1616}
1617
1618void Renderer::SetDepthMode()
1619{
1620 const GLenum glCmpFuncs[8] =
1621 {
1622 GL_NEVER0x0200,
1623 GL_LESS0x0201,
1624 GL_EQUAL0x0202,
1625 GL_LEQUAL0x0203,
1626 GL_GREATER0x0204,
1627 GL_NOTEQUAL0x0205,
1628 GL_GEQUAL0x0206,
1629 GL_ALWAYS0x0207
1630 };
1631
1632 if (bpmem.zmode.testenable)
1633 {
1634 glEnable(GL_DEPTH_TEST0x0B71);
1635 glDepthMask(bpmem.zmode.updateenable ? GL_TRUE1 : GL_FALSE0);
1636 glDepthFunc(glCmpFuncs[bpmem.zmode.func]);
1637 }
1638 else
1639 {
1640 // if the test is disabled write is disabled too
1641 // TODO: When PE performance metrics are being emulated via occlusion queries, we should (probably?) enable depth test with depth function ALWAYS here
1642 glDisable(GL_DEPTH_TEST0x0B71);
1643 glDepthMask(GL_FALSE0);
1644 }
1645}
1646
1647void Renderer::SetLogicOpMode()
1648{
1649
1650 // Logic ops aren't available in GLES3/GLES2
1651#ifndef USE_GLES3
1652 const GLenum glLogicOpCodes[16] =
1653 {
1654 GL_CLEAR0x1500,
1655 GL_AND0x1501,
1656 GL_AND_REVERSE0x1502,
1657 GL_COPY0x1503,
1658 GL_AND_INVERTED0x1504,
1659 GL_NOOP0x1505,
1660 GL_XOR0x1506,
1661 GL_OR0x1507,
1662 GL_NOR0x1508,
1663 GL_EQUIV0x1509,
1664 GL_INVERT0x150A,
1665 GL_OR_REVERSE0x150B,
1666 GL_COPY_INVERTED0x150C,
1667 GL_OR_INVERTED0x150D,
1668 GL_NAND0x150E,
1669 GL_SET0x150F
1670 };
1671
1672 if (bpmem.blendmode.logicopenable)
1673 {
1674 glEnable(GL_COLOR_LOGIC_OP0x0BF2);
1675 glLogicOp(glLogicOpCodes[bpmem.blendmode.logicmode]);
1676 }
1677 else
1678 {
1679 glDisable(GL_COLOR_LOGIC_OP0x0BF2);
1680 }
1681#endif
1682}
1683
1684void Renderer::SetDitherMode()
1685{
1686 if (bpmem.blendmode.dither)
1687 glEnable(GL_DITHER0x0BD0);
1688 else
1689 glDisable(GL_DITHER0x0BD0);
1690}
1691
1692void Renderer::SetLineWidth()
1693{
1694 float fratio = xfregs.viewport.wd != 0 ?
1695 ((float)Renderer::GetTargetWidth() / EFB_WIDTH) : 1.0f;
1696 if (bpmem.lineptwidth.linesize > 0)
1697 // scale by ratio of widths
1698 glLineWidth((float)bpmem.lineptwidth.linesize * fratio / 6.0f);
1699#ifndef USE_GLES3
1700 if (bpmem.lineptwidth.pointsize > 0)
1701 glPointSize((float)bpmem.lineptwidth.pointsize * fratio / 6.0f);
1702#endif
1703}
1704
1705void Renderer::SetSamplerState(int stage, int texindex)
1706{
1707 auto const& tex = bpmem.tex[texindex];
1708 auto const& tm0 = tex.texMode0[stage];
1709 auto const& tm1 = tex.texMode1[stage];
1710
1711 g_sampler_cache->SetSamplerState((texindex * 4) + stage, tm0, tm1);
1712}
1713
1714void Renderer::SetInterlacingMode()
1715{
1716 // TODO
1717}
1718
1719void Renderer::FlipImageData(u8 *data, int w, int h)
1720{
1721 // Flip image upside down. Damn OpenGL.
1722 for (int y = 0; y < h / 2; y++)
1723 {
1724 for(int x = 0; x < w; x++)
1725 {
1726 std::swap(data[(y * w + x) * 3], data[((h - 1 - y) * w + x) * 3]);
1727 std::swap(data[(y * w + x) * 3 + 1], data[((h - 1 - y) * w + x) * 3 + 1]);
1728 std::swap(data[(y * w + x) * 3 + 2], data[((h - 1 - y) * w + x) * 3 + 2]);
1729 }
1730 }
1731}
1732
1733}
1734
1735// TODO: remove
1736extern bool g_aspect_wide;
1737
1738#if defined(HAVE_WX1) && HAVE_WX1
1739void TakeScreenshot(ScrStrct* threadStruct)
1740{
1741 // These will contain the final image size
1742 float FloatW = (float)threadStruct->W;
1743 float FloatH = (float)threadStruct->H;
1744
1745 // Handle aspect ratio for the final ScrStrct to look exactly like what's on screen.
1746 if (g_ActiveConfig.iAspectRatio != ASPECT_STRETCH)
1747 {
1748 bool use16_9 = g_aspect_wide;
1749
1750 // Check for force-settings and override.
1751 if (g_ActiveConfig.iAspectRatio == ASPECT_FORCE_16_9)
1752 use16_9 = true;
1753 else if (g_ActiveConfig.iAspectRatio == ASPECT_FORCE_4_3)
1754 use16_9 = false;
1755
1756 float Ratio = (FloatW / FloatH) / (!use16_9 ? (4.0f / 3.0f) : (16.0f / 9.0f));
1757
1758 // If ratio > 1 the picture is too wide and we have to limit the width.
1759 if (Ratio > 1)
1760 FloatW /= Ratio;
1761 // ratio == 1 or the image is too high, we have to limit the height.
1762 else
1763 FloatH *= Ratio;
1764
1765 // This is a bit expensive on high resolutions
1766 threadStruct->img->Rescale((int)FloatW, (int)FloatH, wxIMAGE_QUALITY_HIGH);
1767 }
1768
1769 // Save the screenshot and finally kill the wxImage object
1770 // This is really expensive when saving to PNG, but not at all when using BMP
1771 threadStruct->img->SaveFile(StrToWxStr(threadStruct->filename),
1772 wxBITMAP_TYPE_PNG);
1773 threadStruct->img->Destroy();
1774
1775 // Show success messages
1776 OSD::AddMessage(StringFromFormat("Saved %i x %i %s", (int)FloatW, (int)FloatH,
1777 threadStruct->filename.c_str()).c_str(), 2000);
1778 delete threadStruct;
1779}
1780#endif
1781
1782namespace OGL
1783{
1784
1785bool Renderer::SaveScreenshot(const std::string &filename, const TargetRectangle &back_rc)
1786{
1787 u32 W = back_rc.GetWidth();
1788 u32 H = back_rc.GetHeight();
1789 u8 *data = (u8 *)malloc((sizeof(u8) * 3 * W * H));
1790 glPixelStorei(GL_PACK_ALIGNMENT0x0D05, 1);
1791
1792 glReadPixels(back_rc.left, back_rc.bottom, W, H, GL_RGB0x1907, GL_UNSIGNED_BYTE0x1401, data);
1793
1794 // Show failure message
1795 if (GL_REPORT_ERROR() != GL_NO_ERROR0)
1796 {
1797 free(data);
1798 OSD::AddMessage("Error capturing or saving screenshot.", 2000);
1799 return false;
1800 }
1801
1802 // Turn image upside down
1803 FlipImageData(data, W, H);
1804
1805#if defined(HAVE_WX1) && HAVE_WX1
1806 // Create wxImage
1807 wxImage *a = new wxImage(W, H, data);
1808
1809 if (scrshotThread.joinable())
1810 scrshotThread.join();
1811
1812 ScrStrct *threadStruct = new ScrStrct;
1813 threadStruct->filename = filename;
1814 threadStruct->img = a;
1815 threadStruct->H = H; threadStruct->W = W;
1816
1817 scrshotThread = std::thread(TakeScreenshot, threadStruct);
1818#ifdef _WIN32
1819 SetThreadPriority(scrshotThread.native_handle(), THREAD_PRIORITY_BELOW_NORMAL);
1820#endif
1821 bool result = true;
1822
1823 OSD::AddMessage("Saving Screenshot... ", 2000);
1824
1825#else
1826 bool result = SaveTGA(filename.c_str(), W, H, data);
1827 free(data);
1828#endif
1829
1830 return result;
1831}
1832
1833}