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 // Resolve our rectangle.
962 FramebufferManager::GetEFBDepthTexture(efbPixelRc);
963 glBindFramebuffer__glewBindFramebuffer(GL_READ_FRAMEBUFFER0x8CA8, FramebufferManager::GetResolvedFramebuffer());
964 }
965
966 u32* depthMap = new u32[targetPixelRcWidth * targetPixelRcHeight];
967
968 glReadPixels(targetPixelRc.left, targetPixelRc.bottom, targetPixelRcWidth, targetPixelRcHeight,
969 GL_DEPTH_COMPONENT0x1902, GL_UNSIGNED_INT0x1405, depthMap);
970 GL_REPORT_ERRORD()(void)0;
971
972 UpdateEFBCache(type, cacheRectIdx, efbPixelRc, targetPixelRc, depthMap);
973
974 delete[] depthMap;
975 }
976
977 u32 xRect = x % EFB_CACHE_RECT_SIZE;
978 u32 yRect = y % EFB_CACHE_RECT_SIZE;
979 z = s_efbCache[0][cacheRectIdx][yRect * EFB_CACHE_RECT_SIZE + xRect];
980
981 // Scale the 32-bit value returned by glReadPixels to a 24-bit
982 // value (GC uses a 24-bit Z-buffer).
983 // TODO: in RE0 this value is often off by one, which causes lighting to disappear
984 if(bpmem.zcontrol.pixel_format == PIXELFMT_RGB565_Z162)
985 {
986 // if Z is in 16 bit format you must return a 16 bit integer
987 z = z >> 16;
988 }
989 else
990 {
991 z = z >> 8;
992 }
993 return z;
994 }
995
996 case PEEK_COLOR: // GXPeekARGB
997 {
998 // Although it may sound strange, this really is A8R8G8B8 and not RGBA or 24-bit...
999
1000 // Tested in Killer 7, the first 8bits represent the alpha value which is used to
1001 // determine if we're aiming at an enemy (0x80 / 0x88) or not (0x70)
1002 // Wind Waker is also using it for the pictograph to determine the color of each pixel
1003
1004 u32 color;
1005
1006 if (!s_efbCacheValid[1][cacheRectIdx])
1007 {
1008 if (s_MSAASamples > 1)
1009 {
1010 // Resolve our rectangle.
1011 FramebufferManager::GetEFBColorTexture(efbPixelRc);
1012 glBindFramebuffer__glewBindFramebuffer(GL_READ_FRAMEBUFFER0x8CA8, FramebufferManager::GetResolvedFramebuffer());
1013 }
1014
1015 u32* colorMap = new u32[targetPixelRcWidth * targetPixelRcHeight];
1016
1017#ifdef USE_GLES3
1018 // XXX: Swap colours
1019 glReadPixels(targetPixelRc.left, targetPixelRc.bottom, targetPixelRcWidth, targetPixelRcHeight,
1020 GL_RGBA0x1908, GL_UNSIGNED_BYTE0x1401, colorMap);
1021#else
1022 glReadPixels(targetPixelRc.left, targetPixelRc.bottom, targetPixelRcWidth, targetPixelRcHeight,
1023 GL_BGRA0x80E1, GL_UNSIGNED_INT_8_8_8_8_REV0x8367, colorMap);
1024#endif
1025 GL_REPORT_ERRORD()(void)0;
1026
1027 UpdateEFBCache(type, cacheRectIdx, efbPixelRc, targetPixelRc, colorMap);
1028
1029 delete[] colorMap;
1030 }
1031
1032 u32 xRect = x % EFB_CACHE_RECT_SIZE;
1033 u32 yRect = y % EFB_CACHE_RECT_SIZE;
1034 color = s_efbCache[1][cacheRectIdx][yRect * EFB_CACHE_RECT_SIZE + xRect];
1035
1036 // check what to do with the alpha channel (GX_PokeAlphaRead)
1037 PixelEngine::UPEAlphaReadReg alpha_read_mode;
1038 PixelEngine::Read16((u16&)alpha_read_mode, PE_ALPHAREAD);
1039
1040 if (bpmem.zcontrol.pixel_format == PIXELFMT_RGBA6_Z241)
1041 {
1042 color = RGBA8ToRGBA6ToRGBA8(color);
1043 }
1044 else if (bpmem.zcontrol.pixel_format == PIXELFMT_RGB565_Z162)
1045 {
1046 color = RGBA8ToRGB565ToRGBA8(color);
1047 }
1048 if(bpmem.zcontrol.pixel_format != PIXELFMT_RGBA6_Z241)
1049 {
1050 color |= 0xFF000000;
1051 }
1052 if(alpha_read_mode.ReadMode == 2) return color; // GX_READ_NONE
1053 else if(alpha_read_mode.ReadMode == 1) return (color | 0xFF000000); // GX_READ_FF
1054 else /*if(alpha_read_mode.ReadMode == 0)*/ return (color & 0x00FFFFFF); // GX_READ_00
1055 }
1056
1057 case POKE_COLOR:
1058 case POKE_Z:
1059 // TODO: Implement. One way is to draw a tiny pixel-sized rectangle at
1060 // the exact location. Note: EFB pokes are susceptible to Z-buffering
1061 // and perhaps blending.
1062 //WARN_LOG(VIDEOINTERFACE, "This is probably some kind of software rendering");
1063 break;
1064
1065 default:
1066 break;
1067 }
1068
1069 return 0;
1070}
1071
1072// Called from VertexShaderManager
1073void Renderer::UpdateViewport(Matrix44& vpCorrection)
1074{
1075 // reversed gxsetviewport(xorig, yorig, width, height, nearz, farz)
1076 // [0] = width/2
1077 // [1] = height/2
1078 // [2] = 16777215 * (farz - nearz)
1079 // [3] = xorig + width/2 + 342
1080 // [4] = yorig + height/2 + 342
1081 // [5] = 16777215 * farz
1082
1083 int scissorXOff = bpmem.scissorOffset.x * 2;
1084 int scissorYOff = bpmem.scissorOffset.y * 2;
1085
1086 // TODO: ceil, floor or just cast to int?
1087 int X = EFBToScaledX((int)ceil(xfregs.viewport.xOrig - xfregs.viewport.wd - (float)scissorXOff));
1088 int Y = EFBToScaledY((int)ceil((float)EFB_HEIGHT - xfregs.viewport.yOrig + xfregs.viewport.ht + (float)scissorYOff));
1089 int Width = EFBToScaledX((int)ceil(2.0f * xfregs.viewport.wd));
1090 int Height = EFBToScaledY((int)ceil(-2.0f * xfregs.viewport.ht));
1091 double GLNear = (xfregs.viewport.farZ - xfregs.viewport.zRange) / 16777216.0f;
1092 double GLFar = xfregs.viewport.farZ / 16777216.0f;
1093 if (Width < 0)
1094 {
1095 X += Width;
1096 Width *= -1;
1097 }
1098 if (Height < 0)
1099 {
1100 Y += Height;
1101 Height *= -1;
1102 }
1103
1104 // OpenGL does not require any viewport correct
1105 Matrix44::LoadIdentity(vpCorrection);
1106
1107 // Update the view port
1108 glViewport(X, Y, Width, Height);
1109 glDepthRangef__glewDepthRangef(GLNear, GLFar);
1110}
1111
1112void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z)
1113{
1114 ResetAPIState();
1115
1116 // color
1117 GLboolean const
1118 color_mask = colorEnable ? GL_TRUE1 : GL_FALSE0,
1119 alpha_mask = alphaEnable ? GL_TRUE1 : GL_FALSE0;
1120 glColorMask(color_mask, color_mask, color_mask, alpha_mask);
1121
1122 glClearColor(
1123 float((color >> 16) & 0xFF) / 255.0f,
1124 float((color >> 8) & 0xFF) / 255.0f,
1125 float((color >> 0) & 0xFF) / 255.0f,
1126 float((color >> 24) & 0xFF) / 255.0f);
1127
1128 // depth
1129 glDepthMask(zEnable ? GL_TRUE1 : GL_FALSE0);
1130
1131 glClearDepthf__glewClearDepthf(float(z & 0xFFFFFF) / float(0xFFFFFF));
1132
1133 // Update rect for clearing the picture
1134 glEnable(GL_SCISSOR_TEST0x0C11);
1135
1136 TargetRectangle const targetRc = ConvertEFBRectangle(rc);
1137 glScissor(targetRc.left, targetRc.bottom, targetRc.GetWidth(), targetRc.GetHeight());
1138
1139 // glColorMask/glDepthMask/glScissor affect glClear (glViewport does not)
1140 glClear(GL_COLOR_BUFFER_BIT0x00004000 | GL_DEPTH_BUFFER_BIT0x00000100);
1141
1142 RestoreAPIState();
1143
1144 ClearEFBCache();
1145}
1146
1147void Renderer::ReinterpretPixelData(unsigned int convtype)
1148{
1149 if (convtype == 0 || convtype == 2)
1150 {
1151 FramebufferManager::ReinterpretPixelData(convtype);
1152 }
1153 else
1154 {
1155 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"
, 1155, "Trying to reinterpret pixel data with unsupported conversion type %d"
, convtype); } } while (0)
;
1156 }
1157}
1158
1159void Renderer::SetBlendMode(bool forceUpdate)
1160{
1161 // 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
1162 // Example: D3DBLEND_DESTALPHA needs to be D3DBLEND_ONE since the result without an alpha channel is assumed to always be 1.
1163 bool target_has_alpha = bpmem.zcontrol.pixel_format == PIXELFMT_RGBA6_Z241;
1164
1165 bool useDstAlpha = !g_ActiveConfig.bDstAlphaPass && bpmem.dstalpha.enable && bpmem.blendmode.alphaupdate && target_has_alpha;
1166 bool useDualSource = useDstAlpha && g_ActiveConfig.backend_info.bSupportsDualSourceBlend;
1167
1168 const GLenum glSrcFactors[8] =
1169 {
1170 GL_ZERO0,
1171 GL_ONE1,
1172 GL_DST_COLOR0x0306,
1173 GL_ONE_MINUS_DST_COLOR0x0307,
1174 (useDualSource) ? GL_SRC1_ALPHA0x8589 : (GLenum)GL_SRC_ALPHA0x0302,
1175 (useDualSource) ? GL_ONE_MINUS_SRC1_ALPHA0x88FB : (GLenum)GL_ONE_MINUS_SRC_ALPHA0x0303,
1176 (target_has_alpha) ? GL_DST_ALPHA0x0304 : (GLenum)GL_ONE1,
1177 (target_has_alpha) ? GL_ONE_MINUS_DST_ALPHA0x0305 : (GLenum)GL_ZERO0
1178 };
1179 const GLenum glDestFactors[8] =
1180 {
1181 GL_ZERO0,
1182 GL_ONE1,
1183 GL_SRC_COLOR0x0300,
1184 GL_ONE_MINUS_SRC_COLOR0x0301,
1185 (useDualSource) ? GL_SRC1_ALPHA0x8589 : (GLenum)GL_SRC_ALPHA0x0302,
1186 (useDualSource) ? GL_ONE_MINUS_SRC1_ALPHA0x88FB : (GLenum)GL_ONE_MINUS_SRC_ALPHA0x0303,
1187 (target_has_alpha) ? GL_DST_ALPHA0x0304 : (GLenum)GL_ONE1,
1188 (target_has_alpha) ? GL_ONE_MINUS_DST_ALPHA0x0305 : (GLenum)GL_ZERO0
1189 };
1190
1191 // blend mode bit mask
1192 // 0 - blend enable
1193 // 1 - dst alpha enabled
1194 // 2 - reverse subtract enable (else add)
1195 // 3-5 - srcRGB function
1196 // 6-8 - dstRGB function
1197
1198 u32 newval = useDualSource << 1;
1199 newval |= bpmem.blendmode.subtract << 2;
1200
1201 if (bpmem.blendmode.subtract)
1202 newval |= 0x0049; // enable blending src 1 dst 1
1203 else if (bpmem.blendmode.blendenable)
1204 {
1205 newval |= 1; // enable blending
1206 newval |= bpmem.blendmode.srcfactor << 3;
1207 newval |= bpmem.blendmode.dstfactor << 6;
1208 }
1209
1210 u32 changes = forceUpdate ? 0xFFFFFFFF : newval ^ s_blendMode;
1211
1212 if (changes & 1)
1213 // blend enable change
1214 (newval & 1) ? glEnable(GL_BLEND0x0BE2) : glDisable(GL_BLEND0x0BE2);
1215
1216 if (changes & 4)
1217 {
1218 // subtract enable change
1219 GLenum equation = newval & 4 ? GL_FUNC_REVERSE_SUBTRACT0x800B : GL_FUNC_ADD0x8006;
1220 GLenum equationAlpha = useDualSource ? GL_FUNC_ADD0x8006 : equation;
1221
1222 glBlendEquationSeparate__glewBlendEquationSeparate(equation, equationAlpha);
1223 }
1224
1225 if (changes & 0x1FA)
1226 {
1227 u32 srcidx = (newval >> 3) & 7;
1228 u32 dstidx = (newval >> 6) & 7;
1229 GLenum srcFactor = glSrcFactors[srcidx];
1230 GLenum dstFactor = glDestFactors[dstidx];
1231
1232 // adjust alpha factors
1233 if (useDualSource)
1234 {
1235 srcidx = GX_BL_ONE1;
1236 dstidx = GX_BL_ZERO0;
1237 }
1238 else
1239 {
1240 // we can't use GL_DST_COLOR or GL_ONE_MINUS_DST_COLOR for source in alpha channel so use their alpha equivalent instead
1241 if (srcidx == GX_BL_DSTCLR2) srcidx = GX_BL_DSTALPHA6;
1242 if (srcidx == GX_BL_INVDSTCLR3) srcidx = GX_BL_INVDSTALPHA7;
1243
1244 // we can't use GL_SRC_COLOR or GL_ONE_MINUS_SRC_COLOR for destination in alpha channel so use their alpha equivalent instead
1245 if (dstidx == GX_BL_SRCCLR2) dstidx = GX_BL_SRCALPHA4;
1246 if (dstidx == GX_BL_INVSRCCLR3) dstidx = GX_BL_INVSRCALPHA5;
1247 }
1248 GLenum srcFactorAlpha = glSrcFactors[srcidx];
1249 GLenum dstFactorAlpha = glDestFactors[dstidx];
1250 // blend RGB change
1251 glBlendFuncSeparate__glewBlendFuncSeparate(srcFactor, dstFactor, srcFactorAlpha, dstFactorAlpha);
1252 }
1253 s_blendMode = newval;
1254}
1255
1256void DumpFrame(const std::vector<u8>& data, int w, int h)
1257{
1258#if defined(HAVE_LIBAV1) || defined(_WIN32)
1259 if (g_ActiveConfig.bDumpFrames && !data.empty())
1260 {
1261 AVIDump::AddFrame(&data[0], w, h);
1262 }
1263#endif
1264}
1265
1266// This function has the final picture. We adjust the aspect ratio here.
1267void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,const EFBRectangle& rc,float Gamma)
1268{
1269 static int w = 0, h = 0;
1270 if (g_bSkipCurrentFrame || (!XFBWrited && !g_ActiveConfig.RealXFBEnabled()) || !fbWidth || !fbHeight)
1271 {
1272 DumpFrame(frame_data, w, h);
1273 Core::Callback_VideoCopiedToXFB(false);
1274 return;
1275 }
1276
1277 if (field == FIELD_LOWER) xfbAddr -= fbWidth * 2;
1278 u32 xfbCount = 0;
1279 const XFBSourceBase* const* xfbSourceList = FramebufferManager::GetXFBSource(xfbAddr, fbWidth, fbHeight, xfbCount);
1280 if (g_ActiveConfig.VirtualXFBEnabled() && (!xfbSourceList || xfbCount == 0))
1281 {
1282 DumpFrame(frame_data, w, h);
1283 Core::Callback_VideoCopiedToXFB(false);
1284 return;
1285 }
1286
1287 ResetAPIState();
1288
1289 PostProcessing::Update(s_backbuffer_width, s_backbuffer_height);
1290 UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height);
1291 TargetRectangle flipped_trc = GetTargetRectangle();
1292
1293 // Flip top and bottom for some reason; TODO: Fix the code to suck less?
1294 int tmp = flipped_trc.top;
1295 flipped_trc.top = flipped_trc.bottom;
1296 flipped_trc.bottom = tmp;
1297
1298 GL_REPORT_ERRORD()(void)0;
1299
1300 // Copy the framebuffer to screen.
1301
1302 const XFBSourceBase* xfbSource = NULL__null;
1303
1304 if(g_ActiveConfig.bUseXFB)
1305 {
1306 // Render to the real/postprocessing buffer now.
1307 PostProcessing::BindTargetFramebuffer();
1308
1309 // draw each xfb source
1310 glBindFramebuffer__glewBindFramebuffer(GL_READ_FRAMEBUFFER0x8CA8, FramebufferManager::GetXFBFramebuffer());
1311
1312 for (u32 i = 0; i < xfbCount; ++i)
1313 {
1314 xfbSource = xfbSourceList[i];
1315
1316 MathUtil::Rectangle<float> drawRc;
1317
1318 if (g_ActiveConfig.bUseRealXFB)
1319 {
1320 drawRc.top = flipped_trc.top;
1321 drawRc.bottom = flipped_trc.bottom;
1322 drawRc.left = flipped_trc.left;
1323 drawRc.right = flipped_trc.right;
1324 }
1325 else
1326 {
1327 // use virtual xfb with offset
1328 int xfbHeight = xfbSource->srcHeight;
1329 int xfbWidth = xfbSource->srcWidth;
1330 int hOffset = ((s32)xfbSource->srcAddr - (s32)xfbAddr) / ((s32)fbWidth * 2);
1331
1332 drawRc.top = flipped_trc.top - hOffset * flipped_trc.GetHeight() / fbHeight;
1333 drawRc.bottom = flipped_trc.top - (hOffset + xfbHeight) * flipped_trc.GetHeight() / fbHeight;
1334 drawRc.left = flipped_trc.left + (flipped_trc.GetWidth() - xfbWidth * flipped_trc.GetWidth() / fbWidth)/2;
1335 drawRc.right = flipped_trc.left + (flipped_trc.GetWidth() + xfbWidth * flipped_trc.GetWidth() / fbWidth)/2;
1336
1337 // The following code disables auto stretch. Kept for reference.
1338 // scale draw area for a 1 to 1 pixel mapping with the draw target
1339 //float vScale = (float)fbHeight / (float)flipped_trc.GetHeight();
1340 //float hScale = (float)fbWidth / (float)flipped_trc.GetWidth();
1341 //drawRc.top *= vScale;
1342 //drawRc.bottom *= vScale;
1343 //drawRc.left *= hScale;
1344 //drawRc.right *= hScale;
1345 }
1346 // Tell the OSD Menu about the current internal resolution
1347 OSDInternalW = xfbSource->sourceRc.GetWidth(); OSDInternalH = xfbSource->sourceRc.GetHeight();
1348
1349 MathUtil::Rectangle<float> sourceRc;
1350 sourceRc.left = xfbSource->sourceRc.left;
1351 sourceRc.right = xfbSource->sourceRc.right;
1352 sourceRc.top = xfbSource->sourceRc.top;
1353 sourceRc.bottom = xfbSource->sourceRc.bottom;
1354
1355 xfbSource->Draw(sourceRc, drawRc, 0, 0);
1356 }
1357 }
1358 else
1359 {
1360 TargetRectangle targetRc = ConvertEFBRectangle(rc);
1361
1362 // for msaa mode, we must resolve the efb content to non-msaa
1363 FramebufferManager::ResolveAndGetRenderTarget(rc);
1364
1365 // Render to the real/postprocessing buffer now. (resolve have changed this in msaa mode)
1366 PostProcessing::BindTargetFramebuffer();
1367
1368 // always the non-msaa fbo
1369 GLuint fb = s_MSAASamples>1?FramebufferManager::GetResolvedFramebuffer():FramebufferManager::GetEFBFramebuffer();
1370
1371 glBindFramebuffer__glewBindFramebuffer(GL_READ_FRAMEBUFFER0x8CA8, fb);
1372 glBlitFramebuffer__glewBlitFramebuffer(targetRc.left, targetRc.bottom, targetRc.right, targetRc.top,
1373 flipped_trc.left, flipped_trc.bottom, flipped_trc.right, flipped_trc.top,
1374 GL_COLOR_BUFFER_BIT0x00004000, GL_LINEAR0x2601);
1375 }
1376
1377 PostProcessing::BlitToScreen();
1378
1379 glBindFramebuffer__glewBindFramebuffer(GL_READ_FRAMEBUFFER0x8CA8, 0);
1380
1381 // Save screenshot
1382 if (s_bScreenshot)
1383 {
1384 std::lock_guard<std::mutex> lk(s_criticalScreenshot);
1385 SaveScreenshot(s_sScreenshotName, flipped_trc);
1386 // Reset settings
1387 s_sScreenshotName.clear();
1388 s_bScreenshot = false;
1389 }
1390
1391 // Frame dumps are handled a little differently in Windows
1392 // Frame dumping disabled entirely on GLES3
1393#ifndef USE_GLES3
1394#if defined _WIN32 || defined HAVE_LIBAV1
1395 if (g_ActiveConfig.bDumpFrames)
1396 {
1397 std::lock_guard<std::mutex> lk(s_criticalScreenshot);
1398 if (frame_data.empty() || w != flipped_trc.GetWidth() ||
1399 h != flipped_trc.GetHeight())
1400 {
1401 w = flipped_trc.GetWidth();
1402 h = flipped_trc.GetHeight();
1403 frame_data.resize(3 * w * h);
1404 }
1405 glPixelStorei(GL_PACK_ALIGNMENT0x0D05, 1);
1406 glReadPixels(flipped_trc.left, flipped_trc.bottom, w, h, GL_BGR0x80E0, GL_UNSIGNED_BYTE0x1401, &frame_data[0]);
1407 if (GL_REPORT_ERROR() == GL_NO_ERROR0 && w > 0 && h > 0)
1408 {
1409 if (!bLastFrameDumped)
1410 {
1411 #ifdef _WIN32
1412 bAVIDumping = AVIDump::Start(EmuWindow::GetParentWnd(), w, h);
1413 #else
1414 bAVIDumping = AVIDump::Start(w, h);
1415 #endif
1416 if (!bAVIDumping)
1417 OSD::AddMessage("AVIDump Start failed", 2000);
1418 else
1419 {
1420 OSD::AddMessage(StringFromFormat(
1421 "Dumping Frames to \"%sframedump0.avi\" (%dx%d RGB24)",
1422 File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), w, h).c_str(), 2000);
1423 }
1424 }
1425 if (bAVIDumping)
1426 {
1427 #ifndef _WIN32
1428 FlipImageData(&frame_data[0], w, h);
1429 #endif
1430
1431 AVIDump::AddFrame(&frame_data[0], w, h);
1432 }
1433
1434 bLastFrameDumped = true;
1435 }
1436 else
1437 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"
, 1437, "Error reading framebuffer"); } } while (0)
;
1438 }
1439 else
1440 {
1441 if (bLastFrameDumped && bAVIDumping)
1442 {
1443 std::vector<u8>().swap(frame_data);
1444 w = h = 0;
1445 AVIDump::Stop();
1446 bAVIDumping = false;
1447 OSD::AddMessage("Stop dumping frames", 2000);
1448 }
1449 bLastFrameDumped = false;
1450 }
1451#else
1452 if (g_ActiveConfig.bDumpFrames)
1453 {
1454 std::lock_guard<std::mutex> lk(s_criticalScreenshot);
1455 std::string movie_file_name;
1456 w = GetTargetRectangle().GetWidth();
1457 h = GetTargetRectangle().GetHeight();
1458 frame_data.resize(3 * w * h);
1459 glPixelStorei(GL_PACK_ALIGNMENT0x0D05, 1);
1460 glReadPixels(GetTargetRectangle().left, GetTargetRectangle().bottom, w, h, GL_BGR0x80E0, GL_UNSIGNED_BYTE0x1401, &frame_data[0]);
1461 if (GL_REPORT_ERROR() == GL_NO_ERROR0)
1462 {
1463 if (!bLastFrameDumped)
1464 {
1465 movie_file_name = File::GetUserPath(D_DUMPFRAMES_IDX) + "framedump.raw";
1466 pFrameDump.Open(movie_file_name, "wb");
1467 if (!pFrameDump)
1468 OSD::AddMessage("Error opening framedump.raw for writing.", 2000);
1469 else
1470 {
1471 OSD::AddMessage(StringFromFormat("Dumping Frames to \"%s\" (%dx%d RGB24)", movie_file_name.c_str(), w, h).c_str(), 2000);
1472 }
1473 }
1474 if (pFrameDump)
1475 {
1476 FlipImageData(&frame_data[0], w, h);
1477 pFrameDump.WriteBytes(&frame_data[0], w * 3 * h);
1478 pFrameDump.Flush();
1479 }
1480 bLastFrameDumped = true;
1481 }
1482 }
1483 else
1484 {
1485 if (bLastFrameDumped)
1486 pFrameDump.Close();
1487 bLastFrameDumped = false;
1488 }
1489#endif
1490#endif
1491 // Finish up the current frame, print some stats
1492
1493 SetWindowSize(fbWidth, fbHeight);
1494
1495 GLInterface->Update(); // just updates the render window position and the backbuffer size
1496
1497 bool xfbchanged = false;
1498
1499 if (FramebufferManagerBase::LastXfbWidth() != fbWidth || FramebufferManagerBase::LastXfbHeight() != fbHeight)
1500 {
1501 xfbchanged = true;
1502 unsigned int const last_w = (fbWidth < 1 || fbWidth > MAX_XFB_WIDTH) ? MAX_XFB_WIDTH : fbWidth;
1503 unsigned int const last_h = (fbHeight < 1 || fbHeight > MAX_XFB_HEIGHT) ? MAX_XFB_HEIGHT : fbHeight;
1504 FramebufferManagerBase::SetLastXfbWidth(last_w);
1505 FramebufferManagerBase::SetLastXfbHeight(last_h);
1506 }
1507
1508 bool WindowResized = false;
1509 int W = (int)GLInterface->GetBackBufferWidth();
1510 int H = (int)GLInterface->GetBackBufferHeight();
1511 if (W != s_backbuffer_width || H != s_backbuffer_height || s_LastEFBScale != g_ActiveConfig.iEFBScale)
1512 {
1513 WindowResized = true;
1514 s_backbuffer_width = W;
1515 s_backbuffer_height = H;
1516 s_LastEFBScale = g_ActiveConfig.iEFBScale;
1517 }
1518
1519 if (xfbchanged || WindowResized || (s_LastMultisampleMode != g_ActiveConfig.iMultisampleMode))
1520 {
1521 UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height);
1522
1523 if (CalculateTargetSize(s_backbuffer_width, s_backbuffer_height) || s_LastMultisampleMode != g_ActiveConfig.iMultisampleMode)
1524 {
1525 s_LastMultisampleMode = g_ActiveConfig.iMultisampleMode;
1526 s_MSAASamples = GetNumMSAASamples(s_LastMultisampleMode);
1527 s_MSAACoverageSamples = GetNumMSAACoverageSamples(s_LastMultisampleMode);
1528 ApplySSAASettings();
1529
1530 delete g_framebuffer_manager;
1531 g_framebuffer_manager = new FramebufferManager(s_target_width, s_target_height,
1532 s_MSAASamples, s_MSAACoverageSamples);
1533 }
1534 }
1535
1536 if (XFBWrited)
1537 s_fps = UpdateFPSCounter();
1538 // ---------------------------------------------------------------------
1539 GL_REPORT_ERRORD()(void)0;
1540
1541 glEnable(GL_BLEND0x0BE2);
1542 glBlendFunc(GL_SRC_ALPHA0x0302, GL_ONE_MINUS_SRC_ALPHA0x0303);
1543
1544 DrawDebugInfo();
1545 DrawDebugText();
1546
1547 GL_REPORT_ERRORD()(void)0;
1548
1549 // Do our OSD callbacks
1550 OSD::DoCallbacks(OSD::OSD_ONFRAME);
1551 OSD::DrawMessages();
1552 GL_REPORT_ERRORD()(void)0;
1553
1554 // Copy the rendered frame to the real window
1555 GLInterface->Swap();
1556
1557 GL_REPORT_ERRORD()(void)0;
1558
1559 // Clear framebuffer
1560 if(!g_ActiveConfig.bAnaglyphStereo)
1561 {
1562 glClearColor(0, 0, 0, 0);
1563 glClear(GL_COLOR_BUFFER_BIT0x00004000 | GL_DEPTH_BUFFER_BIT0x00000100 | GL_STENCIL_BUFFER_BIT0x00000400);
1564 }
1565
1566 GL_REPORT_ERRORD()(void)0;
1567
1568 if(s_vsync != g_ActiveConfig.IsVSync())
1569 {
1570 s_vsync = g_ActiveConfig.IsVSync();
1571 GLInterface->SwapInterval(s_vsync);
1572 }
1573
1574 // Clean out old stuff from caches. It's not worth it to clean out the shader caches.
1575 DLCache::ProgressiveCleanup();
1576 TextureCache::Cleanup();
1577
1578 frameCount++;
1579
1580 GFX_DEBUGGER_PAUSE_AT(NEXT_FRAME, true){if (((GFXDebuggerToPauseAtNext & NEXT_FRAME) && --
GFXDebuggerEventToPauseCount<=0) || GFXDebuggerPauseFlag) GFXDebuggerToPause
(true);}
;
1581
1582 // Begin new frame
1583 // Set default viewport and scissor, for the clear to work correctly
1584 // New frame
1585 stats.ResetFrame();
1586
1587 // Render to the framebuffer.
1588 FramebufferManager::SetFramebuffer(0);
1589
1590 GL_REPORT_ERRORD()(void)0;
1591
1592 RestoreAPIState();
1593
1594 GL_REPORT_ERRORD()(void)0;
1595 g_Config.iSaveTargetId = 0;
1596
1597 UpdateActiveConfig();
1598 TextureCache::OnConfigChanged(g_ActiveConfig);
1599
1600 // For testing zbuffer targets.
1601 // Renderer::SetZBufferRender();
1602 // SaveTexture("tex.tga", GL_TEXTURE_2D, s_FakeZTarget,
1603 // GetTargetWidth(), GetTargetHeight());
1604 Core::Callback_VideoCopiedToXFB(XFBWrited || (g_ActiveConfig.bUseXFB && g_ActiveConfig.bUseRealXFB));
1605 XFBWrited = false;
1606
1607 // Invalidate EFB cache
1608 ClearEFBCache();
1609}
1610
1611// ALWAYS call RestoreAPIState for each ResetAPIState call you're doing
1612void Renderer::ResetAPIState()
1613{
1614 // Gets us to a reasonably sane state where it's possible to do things like
1615 // image copies with textured quads, etc.
1616 glDisable(GL_SCISSOR_TEST0x0C11);
1617 glDisable(GL_DEPTH_TEST0x0B71);
1618 glDisable(GL_CULL_FACE0x0B44);
1619 glDisable(GL_BLEND0x0BE2);
1620 glDepthMask(GL_FALSE0);
1621 glColorMask(GL_TRUE1, GL_TRUE1, GL_TRUE1, GL_TRUE1);
1622}
1623
1624void Renderer::RestoreAPIState()
1625{
1626 // Gets us back into a more game-like state.
1627 glEnable(GL_SCISSOR_TEST0x0C11);
1628 SetGenerationMode();
1629 BPFunctions::SetScissor();
1630 SetColorMask();
1631 SetDepthMode();
1632 SetBlendMode(true);
1633 VertexShaderManager::SetViewportChanged();
1634
1635#ifndef USE_GLES3
1636 glPolygonMode(GL_FRONT_AND_BACK0x0408, g_ActiveConfig.bWireFrame ? GL_LINE0x1B01 : GL_FILL0x1B02);
1637#endif
1638
1639 VertexManager *vm = (OGL::VertexManager*)g_vertex_manager;
1640 glBindBuffer__glewBindBuffer(GL_ARRAY_BUFFER0x8892, vm->m_vertex_buffers);
1641 vm->m_last_vao = 0;
1642
1643 TextureCache::SetStage();
1644}
1645
1646void Renderer::SetGenerationMode()
1647{
1648 // none, ccw, cw, ccw
1649 if (bpmem.genMode.cullmode > 0)
1650 {
1651 glEnable(GL_CULL_FACE0x0B44);
1652 glFrontFace(bpmem.genMode.cullmode == 2 ? GL_CCW0x0901 : GL_CW0x0900);
1653 }
1654 else
1655 glDisable(GL_CULL_FACE0x0B44);
1656}
1657
1658void Renderer::SetDepthMode()
1659{
1660 const GLenum glCmpFuncs[8] =
1661 {
1662 GL_NEVER0x0200,
1663 GL_LESS0x0201,
1664 GL_EQUAL0x0202,
1665 GL_LEQUAL0x0203,
1666 GL_GREATER0x0204,
1667 GL_NOTEQUAL0x0205,
1668 GL_GEQUAL0x0206,
1669 GL_ALWAYS0x0207
1670 };
1671
1672 if (bpmem.zmode.testenable)
1673 {
1674 glEnable(GL_DEPTH_TEST0x0B71);
1675 glDepthMask(bpmem.zmode.updateenable ? GL_TRUE1 : GL_FALSE0);
1676 glDepthFunc(glCmpFuncs[bpmem.zmode.func]);
1677 }
1678 else
1679 {
1680 // if the test is disabled write is disabled too
1681 // TODO: When PE performance metrics are being emulated via occlusion queries, we should (probably?) enable depth test with depth function ALWAYS here
1682 glDisable(GL_DEPTH_TEST0x0B71);
1683 glDepthMask(GL_FALSE0);
1684 }
1685}
1686
1687void Renderer::SetLogicOpMode()
1688{
1689
1690 // Logic ops aren't available in GLES3/GLES2
1691#ifndef USE_GLES3
1692 const GLenum glLogicOpCodes[16] =
1693 {
1694 GL_CLEAR0x1500,
1695 GL_AND0x1501,
1696 GL_AND_REVERSE0x1502,
1697 GL_COPY0x1503,
1698 GL_AND_INVERTED0x1504,
1699 GL_NOOP0x1505,
1700 GL_XOR0x1506,
1701 GL_OR0x1507,
1702 GL_NOR0x1508,
1703 GL_EQUIV0x1509,
1704 GL_INVERT0x150A,
1705 GL_OR_REVERSE0x150B,
1706 GL_COPY_INVERTED0x150C,
1707 GL_OR_INVERTED0x150D,
1708 GL_NAND0x150E,
1709 GL_SET0x150F
1710 };
1711
1712 if (bpmem.blendmode.logicopenable)
1713 {
1714 glEnable(GL_COLOR_LOGIC_OP0x0BF2);
1715 glLogicOp(glLogicOpCodes[bpmem.blendmode.logicmode]);
1716 }
1717 else
1718 {
1719 glDisable(GL_COLOR_LOGIC_OP0x0BF2);
1720 }
1721#endif
1722}
1723
1724void Renderer::SetDitherMode()
1725{
1726 if (bpmem.blendmode.dither)
1727 glEnable(GL_DITHER0x0BD0);
1728 else
1729 glDisable(GL_DITHER0x0BD0);
1730}
1731
1732void Renderer::SetLineWidth()
1733{
1734 float fratio = xfregs.viewport.wd != 0 ?
1735 ((float)Renderer::GetTargetWidth() / EFB_WIDTH) : 1.0f;
1736 if (bpmem.lineptwidth.linesize > 0)
1737 // scale by ratio of widths
1738 glLineWidth((float)bpmem.lineptwidth.linesize * fratio / 6.0f);
1739#ifndef USE_GLES3
1740 if (bpmem.lineptwidth.pointsize > 0)
1741 glPointSize((float)bpmem.lineptwidth.pointsize * fratio / 6.0f);
1742#endif
1743}
1744
1745void Renderer::SetSamplerState(int stage, int texindex)
1746{
1747 auto const& tex = bpmem.tex[texindex];
1748 auto const& tm0 = tex.texMode0[stage];
1749 auto const& tm1 = tex.texMode1[stage];
1750
1751 g_sampler_cache->SetSamplerState((texindex * 4) + stage, tm0, tm1);
1752}
1753
1754void Renderer::SetInterlacingMode()
1755{
1756 // TODO
1757}
1758
1759void Renderer::FlipImageData(u8 *data, int w, int h)
1760{
1761 // Flip image upside down. Damn OpenGL.
1762 for (int y = 0; y < h / 2; y++)
1763 {
1764 for(int x = 0; x < w; x++)
1765 {
1766 std::swap(data[(y * w + x) * 3], data[((h - 1 - y) * w + x) * 3]);
1767 std::swap(data[(y * w + x) * 3 + 1], data[((h - 1 - y) * w + x) * 3 + 1]);
1768 std::swap(data[(y * w + x) * 3 + 2], data[((h - 1 - y) * w + x) * 3 + 2]);
1769 }
1770 }
1771}
1772
1773}
1774
1775// TODO: remove
1776extern bool g_aspect_wide;
1777
1778#if defined(HAVE_WX1) && HAVE_WX1
1779void TakeScreenshot(ScrStrct* threadStruct)
1780{
1781 // These will contain the final image size
1782 float FloatW = (float)threadStruct->W;
1783 float FloatH = (float)threadStruct->H;
1784
1785 // Handle aspect ratio for the final ScrStrct to look exactly like what's on screen.
1786 if (g_ActiveConfig.iAspectRatio != ASPECT_STRETCH)
1787 {
1788 bool use16_9 = g_aspect_wide;
1789
1790 // Check for force-settings and override.
1791 if (g_ActiveConfig.iAspectRatio == ASPECT_FORCE_16_9)
1792 use16_9 = true;
1793 else if (g_ActiveConfig.iAspectRatio == ASPECT_FORCE_4_3)
1794 use16_9 = false;
1795
1796 float Ratio = (FloatW / FloatH) / (!use16_9 ? (4.0f / 3.0f) : (16.0f / 9.0f));
1797
1798 // If ratio > 1 the picture is too wide and we have to limit the width.
1799 if (Ratio > 1)
1800 FloatW /= Ratio;
1801 // ratio == 1 or the image is too high, we have to limit the height.
1802 else
1803 FloatH *= Ratio;
1804
1805 // This is a bit expensive on high resolutions
1806 threadStruct->img->Rescale((int)FloatW, (int)FloatH, wxIMAGE_QUALITY_HIGH);
1807 }
1808
1809 // Save the screenshot and finally kill the wxImage object
1810 // This is really expensive when saving to PNG, but not at all when using BMP
1811 threadStruct->img->SaveFile(StrToWxStr(threadStruct->filename),
1812 wxBITMAP_TYPE_PNG);
1813 threadStruct->img->Destroy();
1814
1815 // Show success messages
1816 OSD::AddMessage(StringFromFormat("Saved %i x %i %s", (int)FloatW, (int)FloatH,
1817 threadStruct->filename.c_str()), 2000);
1818 delete threadStruct;
1819}
1820#endif
1821
1822namespace OGL
1823{
1824
1825bool Renderer::SaveScreenshot(const std::string &filename, const TargetRectangle &back_rc)
1826{
1827 u32 W = back_rc.GetWidth();
1828 u32 H = back_rc.GetHeight();
1829 u8 *data = (u8 *)malloc((sizeof(u8) * 3 * W * H));
1830 glPixelStorei(GL_PACK_ALIGNMENT0x0D05, 1);
1831
1832 glReadPixels(back_rc.left, back_rc.bottom, W, H, GL_RGB0x1907, GL_UNSIGNED_BYTE0x1401, data);
1833
1834 // Show failure message
1835 if (GL_REPORT_ERROR() != GL_NO_ERROR0)
1836 {
1837 free(data);
1838 OSD::AddMessage("Error capturing or saving screenshot.", 2000);
1839 return false;
1840 }
1841
1842 // Turn image upside down
1843 FlipImageData(data, W, H);
1844
1845#if defined(HAVE_WX1) && HAVE_WX1
1846 // Create wxImage
1847 wxImage *a = new wxImage(W, H, data);
1848
1849 if (scrshotThread.joinable())
1850 scrshotThread.join();
1851
1852 ScrStrct *threadStruct = new ScrStrct;
1853 threadStruct->filename = filename;
1854 threadStruct->img = a;
1855 threadStruct->H = H; threadStruct->W = W;
1856
1857 scrshotThread = std::thread(TakeScreenshot, threadStruct);
1858#ifdef _WIN32
1859 SetThreadPriority(scrshotThread.native_handle(), THREAD_PRIORITY_BELOW_NORMAL);
1860#endif
1861 bool result = true;
1862
1863 OSD::AddMessage("Saving Screenshot... ", 2000);
1864
1865#else
1866 bool result = SaveTGA(filename.c_str(), W, H, data);
1867 free(data);
1868#endif
1869
1870 return result;
1871}
1872
1873}