Bug Summary

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