Bug Summary

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

Annotated Source Code

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