Bug Summary

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