diff --git a/src/gpu/framebuffer.cpp b/src/gpu/framebuffer.cpp index 237608c8..dd22defe 100644 --- a/src/gpu/framebuffer.cpp +++ b/src/gpu/framebuffer.cpp @@ -41,7 +41,9 @@ class FramebufferData { friend class Framebuffer; + ibox2 m_saved_viewport; ivec2 m_size; + bool m_bound; #if defined USE_D3D9 IDirect3DTexture9 *m_texture; @@ -288,6 +290,7 @@ Framebuffer::Framebuffer(ivec2 size, FramebufferFormat fbo_format) : m_data(new FramebufferData) { m_data->m_size = size; + m_data->m_bound = false; #if defined USE_D3D9 if (FAILED(g_d3ddevice->CreateTexture(size.x, size.y, 1, D3DUSAGE_RENDERTARGET, @@ -370,7 +373,11 @@ Framebuffer::Framebuffer(ivec2 size, FramebufferFormat fbo_format) "invalid framebuffer status 0x%x", status); # endif - Unbind(); +# if GL_VERSION_1_1 || GL_ES_VERSION_2_0 + glBindFramebuffer(GL_FRAMEBUFFER, 0); +# else + glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0); +# endif #endif } @@ -412,6 +419,8 @@ ivec2 Framebuffer::GetSize() const void Framebuffer::Bind() { + ASSERT(!m_data->m_bound, "trying to bind an already bound framebuffer"); + #if defined USE_D3D9 || defined _XBOX if (FAILED(g_d3ddevice->GetRenderTarget(0, &m_data->m_back_surface))) Abort(); @@ -423,34 +432,40 @@ void Framebuffer::Bind() # else glBindFramebufferOES(GL_FRAMEBUFFER_OES, m_data->m_fbo); # endif - //change viewport draw size - Video::SetCustomSize(m_data->m_size); #endif + + /* FIXME: this should be done in the RenderContext object + * instead, maybe by getting rid of Framebuffer::Bind() and + * creating RenderContext::SetFramebuffer() instead. */ + m_data->m_saved_viewport = g_renderer->GetViewport(); + g_renderer->SetViewport(ibox2(ivec2(0), m_data->m_size)); + m_data->m_bound = true; } void Framebuffer::Unbind() { -#if defined USE_D3D9 - if (FAILED(g_d3ddevice->SetRenderTarget(0, m_data->m_back_surface))) - Abort(); - m_data->m_back_surface->Release(); -#elif defined _XBOX + ASSERT(m_data->m_bound, "trying to unbind an unbound framebuffer"); + +#if defined USE_D3D9 || defined _XBOX +# if defined _XBOX if (FAILED(g_d3ddevice->Resolve(D3DRESOLVE_RENDERTARGET0, nullptr, m_data->m_texture, nullptr, 0, 0, nullptr, 0, 0, nullptr))) Abort(); +# endif if (FAILED(g_d3ddevice->SetRenderTarget(0, m_data->m_back_surface))) Abort(); m_data->m_back_surface->Release(); #else - //Restore viewport draw size - Video::RestoreSize(); # if GL_VERSION_1_1 || GL_ES_VERSION_2_0 glBindFramebuffer(GL_FRAMEBUFFER, 0); # else glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0); # endif #endif + + g_renderer->SetViewport(m_data->m_saved_viewport); + m_data->m_bound = false; } } /* namespace lol */ diff --git a/src/gpu/rendercontext.cpp b/src/gpu/rendercontext.cpp index 56823b1e..d6c8d61e 100644 --- a/src/gpu/rendercontext.cpp +++ b/src/gpu/rendercontext.cpp @@ -54,17 +54,13 @@ class RenderContextData private: Scene *m_scene; + TrackedState m_viewport; TrackedState m_clear_color; - TrackedState m_clear_depth; - TrackedState m_alpha_func; TrackedState m_alpha_value; - TrackedState m_blend_src, m_blend_dst; - TrackedState m_depth_func; - TrackedState m_face_culling; }; @@ -80,6 +76,9 @@ RenderContext::RenderContext() RenderContext::~RenderContext() { + if (m_data->m_viewport.HasChanged()) + g_renderer->SetViewport(m_data->m_viewport.GetValue()); + if (m_data->m_clear_color.HasChanged()) g_renderer->SetClearColor(m_data->m_clear_color.GetValue()); @@ -103,6 +102,14 @@ RenderContext::~RenderContext() delete m_data; } +void RenderContext::SetViewport(ibox2 viewport) +{ + if (!m_data->m_viewport.HasChanged()) + m_data->m_viewport.TrackValue(g_renderer->GetViewport()); + + g_renderer->SetViewport(viewport); +} + void RenderContext::SetClearColor(vec4 color) { if (!m_data->m_clear_color.HasChanged()) diff --git a/src/gpu/renderer.cpp b/src/gpu/renderer.cpp index 07053056..434610e4 100644 --- a/src/gpu/renderer.cpp +++ b/src/gpu/renderer.cpp @@ -53,6 +53,7 @@ class RendererData friend class Renderer; private: + ibox2 m_viewport; vec4 m_clear_color; float m_clear_depth; AlphaFunc m_alpha_func; @@ -72,7 +73,7 @@ private: * Public Renderer class */ -Renderer::Renderer() +Renderer::Renderer(ivec2 size) : m_data(new RendererData()) { #if defined USE_D3D9 || defined _XBOX @@ -91,6 +92,9 @@ Renderer::Renderer() #endif /* Initialise rendering states */ + m_data->m_viewport = ibox2(0, 0, 0, 0); + SetViewport(ibox2(vec2(0), size)); + m_data->m_clear_color = vec4(-1.f); SetClearColor(vec4(0.1f, 0.2f, 0.3f, 1.0f)); @@ -126,12 +130,41 @@ Renderer::~Renderer() delete m_data; } +/* + * Viewport dimensions + */ + +void Renderer::SetViewport(ibox2 viewport) +{ + if (m_data->m_viewport == viewport) + return; + +#if defined USE_D3D9 || defined _XBOX + D3DVIEWPORT9 vp = { viewport.A.x, viewport.A.y, + viewport.B.x, viewport.B.y, + 0.0f, 1.0f }; + m_data->m_d3d_dev->SetViewport(&vp); +#else + glViewport(viewport.A.x, viewport.A.y, viewport.B.x, viewport.B.y); +#endif + + m_data->m_viewport = viewport; +} + +ibox2 Renderer::GetViewport() const +{ + return m_data->m_viewport; +} + /* * Clear color */ void Renderer::SetClearColor(vec4 color) { + if (m_data->m_clear_color == color) + return; + #if defined USE_D3D9 || defined _XBOX /* Nothing to do */ #else @@ -152,6 +185,9 @@ vec4 Renderer::GetClearColor() const void Renderer::SetClearDepth(float depth) { + if (m_data->m_clear_depth == depth) + return; + #if defined USE_D3D9 || defined _XBOX /* Nothing to do */ #elif defined HAVE_GLES_2X diff --git a/src/lol/gpu/rendercontext.h b/src/lol/gpu/rendercontext.h index 92e14d0f..9c7e2a74 100644 --- a/src/lol/gpu/rendercontext.h +++ b/src/lol/gpu/rendercontext.h @@ -27,6 +27,7 @@ public: RenderContext(); ~RenderContext(); + void SetViewport(ibox2 viewport); void SetClearColor(vec4 color); void SetClearDepth(float depth); void SetAlphaFunc(AlphaFunc func, float alpha); diff --git a/src/lol/gpu/renderer.h b/src/lol/gpu/renderer.h index 91b29b2b..68e69128 100644 --- a/src/lol/gpu/renderer.h +++ b/src/lol/gpu/renderer.h @@ -115,10 +115,13 @@ private: /* Only the Video class can create a renderer for now. */ friend class Video; - Renderer(); + Renderer(ivec2 size); ~Renderer(); public: + void SetViewport(ibox2 viewport); + ibox2 GetViewport() const; + void SetClearColor(vec4 color); vec4 GetClearColor() const; diff --git a/src/video.cpp b/src/video.cpp index e0a7c5b2..e2bd8881 100644 --- a/src/video.cpp +++ b/src/video.cpp @@ -48,7 +48,6 @@ class VideoData friend class Video; private: - static ivec2 saved_viewport; static DebugRenderMode render_mode; #if defined USE_D3D9 || defined _XBOX # if defined USE_D3D9 @@ -61,7 +60,6 @@ private: #endif }; -ivec2 VideoData::saved_viewport(0, 0); DebugRenderMode VideoData::render_mode = DebugRenderMode::Default; #if defined USE_D3D9 || defined _XBOX @@ -95,8 +93,6 @@ void Video::Setup(ivec2 size) size = lol::min(size, ivec2(VideoMode.dwDisplayWidth, VideoMode.dwDisplayHeight); # endif - VideoData::saved_viewport = size; - D3DPRESENT_PARAMETERS d3dpp; memset(&d3dpp, 0, sizeof(d3dpp)); d3dpp.BackBufferWidth = size.x; @@ -123,51 +119,16 @@ void Video::Setup(ivec2 size) g_d3ddevice = VideoData::d3d_dev; - g_renderer = new Renderer(); + g_renderer = new Renderer(size); #else /* Initialise OpenGL */ - g_renderer = new Renderer(); - - glViewport(0, 0, size.x, size.y); - VideoData::saved_viewport = size; + g_renderer = new Renderer(size); #endif /* Initialise reasonable scene default properties */ SetDebugRenderMode(DebugRenderMode::Default); } -void Video::SetCustomSize(ivec2 size) -{ - ivec4 current_size(0); -#if defined USE_D3D9 || defined _XBOX -# define STR0(x) #x -# define STR(x) STR0(x) -# pragma message(__FILE__ "(" STR(__LINE__) "): warning: Video::SetSize() not implemented") -#elif defined __CELLOS_LV2__ - // FIXME: use psglCreateDeviceAuto && psglGetDeviceDimensions -#else - glGetIntegerv(GL_VIEWPORT, (GLint*)¤t_size); - if (current_size.zw != size) - glViewport(0, 0, size.x, size.y); -#endif -} - -void Video::RestoreSize() -{ - ivec4 current_size(0); -#if defined USE_D3D9 || defined _XBOX -# define STR0(x) #x -# define STR(x) STR0(x) -# pragma message(__FILE__ "(" STR(__LINE__) "): warning: Video::SetSize() not implemented") -#elif defined __CELLOS_LV2__ - // FIXME: use psglCreateDeviceAuto && psglGetDeviceDimensions -#else - glGetIntegerv(GL_VIEWPORT, (GLint*)¤t_size); - if (current_size.zw != VideoData::saved_viewport) - glViewport(0, 0, VideoData::saved_viewport.x, VideoData::saved_viewport.y); -#endif -} - void Video::SetDebugRenderMode(DebugRenderMode d) { switch(d) @@ -243,10 +204,6 @@ void Video::Clear(ClearMask m) g_renderer->GetClearDepth(), 0))) Abort(); #else - /* FIXME: is this necessary here? */ - ivec2 size = GetSize(); - glViewport(0, 0, size.x, size.y); - GLbitfield mask = 0; if (m & ClearMask::Color) mask |= GL_COLOR_BUFFER_BIT; @@ -302,19 +259,9 @@ void Video::Capture(uint32_t *buffer) ivec2 Video::GetSize() { -#if defined USE_D3D9 || defined _XBOX - return VideoData::saved_viewport; -#elif 1 - /* GetSize() is called too often on the game thread; we cannot rely on - * the GL context at this point */ - return VideoData::saved_viewport; -#elif defined __CELLOS_LV2__ - // FIXME: use psglCreateDeviceAuto && psglGetDeviceDimensions -#else - GLint v[4]; - glGetIntegerv(GL_VIEWPORT, v); - return ivec2(v[2], v[3]); -#endif + ibox2 viewport = g_renderer->GetViewport(); + + return viewport.B - viewport.A; } } /* namespace lol */ diff --git a/src/video.h b/src/video.h index 4eeb0952..846e6a48 100644 --- a/src/video.h +++ b/src/video.h @@ -68,8 +68,6 @@ public: static void Setup(ivec2 size); static void Destroy(); - static void SetCustomSize(ivec2 size); - static void RestoreSize(); static void SetDebugRenderMode(DebugRenderMode d); static DebugRenderMode GetDebugRenderMode(); static void Clear(ClearMask m);