Bug Summary

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