Skip to content
Snippets Groups Projects
Commit 080f8475 authored by bunnei's avatar bunnei
Browse files

added initial renderer code

parent e4d1ad4b
No related branches found
No related tags found
No related merge requests found
......@@ -51,6 +51,9 @@ public:
~RendererBase() {
}
/// Swap buffers (render frame)
virtual void SwapBuffers() = 0;
/**
* Blits the EFB to the external framebuffer (XFB)
* @param src_rect Source rectangle in EFB to copy
......@@ -71,6 +74,24 @@ public:
virtual void Clear(const Rect& rect, bool enable_color, bool enable_alpha, bool enable_z,
u32 color, u32 z) = 0;
/// Sets the renderer viewport location, width, and height
virtual void SetViewport(int x, int y, int width, int height) = 0;
/// Sets the renderer depthrange, znear and zfar
virtual void SetDepthRange(double znear, double zfar) = 0;
/* Sets the scissor box
* @param rect Renderer rectangle to set scissor box to
*/
virtual void SetScissorBox(const Rect& rect) = 0;
/**
* Sets the line and point size
* @param line_width Line width to use
* @param point_size Point size to use
*/
virtual void SetLinePointSize(f32 line_width, f32 point_size) = 0;
/**
* Set a specific render mode
* @param flag Render flags mode to enable
......@@ -95,11 +116,6 @@ public:
/// Shutdown the renderer
virtual void ShutDown() = 0;
/// Converts EFB rectangle coordinates to renderer rectangle coordinates
//static Rect EFBToRendererRect(const Rect& rect) {
// return Rect(rect.x0_, kGCEFBHeight - rect.y0_, rect.x1_, kGCEFBHeight - rect.y1_);
//}
// Getter/setter functions:
// ------------------------
......
/**
* Copyright (C) 2014 Citra Emulator
*
* @file renderer_opengl.cpp
* @author bunnei
* @date 2014-04-05
* @brief Renderer for OpenGL 3.x
*
* @section LICENSE
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details at
* http://www.gnu.org/copyleft/gpl.html
*
* Official project repository can be found at:
* http://code.google.com/p/gekko-gc-emu/
*/
#include "video_core.h"
#include "renderer_opengl/renderer_opengl.h"
/// RendererOpenGL constructor
RendererOpenGL::RendererOpenGL() {
memset(fbo_, 0, sizeof(fbo_));
memset(fbo_rbo_, 0, sizeof(fbo_rbo_));
memset(fbo_depth_buffers_, 0, sizeof(fbo_depth_buffers_));
resolution_width_ = max(VideoCore::kScreenTopWidth, VideoCore::kScreenBottomWidth);
resolution_height_ = VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight;
}
/// RendererOpenGL destructor
RendererOpenGL::~RendererOpenGL() {
}
/// Swap buffers (render frame)
void RendererOpenGL::SwapBuffers() {
glClearColor(1.0f, 1.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
ResetRenderState();
// EFB->XFB copy
// TODO(bunnei): This is a hack and does not belong here. The copy should be triggered by some
// register write We're also treating both framebuffers as a single one in OpenGL.
Rect framebuffer_size(0, 0, VideoCore::kScreenTopWidth,
VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight);
CopyToXFB(framebuffer_size, framebuffer_size);
// XFB->Window copy
RenderFramebuffer();
// Swap buffers
render_window_->PollEvents();
render_window_->SwapBuffers();
// Switch back to EFB and clear
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_[kFramebuffer_EFB]);
RestoreRenderState();
}
/**
* Blits the EFB to the external framebuffer (XFB)
* @param src_rect Source rectangle in EFB to copy
* @param dst_rect Destination rectangle in EFB to copy to
* @param dest_height Destination height in pixels
*/
void RendererOpenGL::CopyToXFB(const Rect& src_rect, const Rect& dst_rect) {
ResetRenderState();
// Render target is destination framebuffer
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_[kFramebuffer_VirtualXFB]);
glViewport(0, 0, resolution_width_, resolution_height_);
// Render source is our EFB
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_[kFramebuffer_EFB]);
glReadBuffer(GL_COLOR_ATTACHMENT0);
// Blit
glBlitFramebuffer(src_rect.x0_, src_rect.y0_, src_rect.x1_, src_rect.y1_,
dst_rect.x0_, dst_rect.y1_, dst_rect.x1_, dst_rect.y0_,
GL_COLOR_BUFFER_BIT, GL_LINEAR);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
RestoreRenderState();
}
/**
* Clear the screen
* @param rect Screen rectangle to clear
* @param enable_color Enable color clearing
* @param enable_alpha Enable alpha clearing
* @param enable_z Enable depth clearing
* @param color Clear color
* @param z Clear depth
*/
void RendererOpenGL::Clear(const Rect& rect, bool enable_color, bool enable_alpha, bool enable_z,
u32 color, u32 z) {
GLboolean const color_mask = enable_color ? GL_TRUE : GL_FALSE;
GLboolean const alpha_mask = enable_alpha ? GL_TRUE : GL_FALSE;
ResetRenderState();
// Clear color
glColorMask(color_mask, color_mask, color_mask, alpha_mask);
glClearColor(float((color >> 16) & 0xFF) / 255.0f, float((color >> 8) & 0xFF) / 255.0f,
float((color >> 0) & 0xFF) / 255.0f, float((color >> 24) & 0xFF) / 255.0f);
// Clear depth
glDepthMask(enable_z ? GL_TRUE : GL_FALSE);
glClearDepth(float(z & 0xFFFFFF) / float(0xFFFFFF));
// Specify the rectangle of the EFB to clear
glEnable(GL_SCISSOR_TEST);
glScissor(rect.x0_, rect.y1_, rect.width(), rect.height());
// Clear it!
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
RestoreRenderState();
}
/// Sets the renderer viewport location, width, and height
void RendererOpenGL::SetViewport(int x, int y, int width, int height) {
glViewport(x, y, width, height);
}
/// Sets the renderer depthrange, znear and zfar
void RendererOpenGL::SetDepthRange(double znear, double zfar) {
glDepthRange(znear, zfar);
}
/* Sets the scissor box
* @param rect Renderer rectangle to set scissor box to
*/
void RendererOpenGL::SetScissorBox(const Rect& rect) {
glScissor(rect.x0_, rect.y1_, rect.width(), rect.height());
}
/**
* Sets the line and point size
* @param line_width Line width to use
* @param point_size Point size to use
*/
void RendererOpenGL::SetLinePointSize(f32 line_width, f32 point_size) {
glLineWidth((GLfloat)line_width);
glPointSize((GLfloat)point_size);
}
/**
* Set a specific render mode
* @param flag Render flags mode to enable
*/
void RendererOpenGL::SetMode(kRenderMode flags) {
if(flags & kRenderMode_ZComp) {
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
}
if(flags & kRenderMode_Multipass) {
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
glDepthFunc(GL_EQUAL);
}
if (flags & kRenderMode_UseDstAlpha) {
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
glDisable(GL_BLEND);
}
last_mode_ |= flags;
}
/// Reset the full renderer API to the NULL state
void RendererOpenGL::ResetRenderState() {
glDisable(GL_SCISSOR_TEST);
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glDisable(GL_BLEND);
glDepthMask(GL_FALSE);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
}
/// Restore the full renderer API state - As the game set it
void RendererOpenGL::RestoreRenderState() {
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_[kFramebuffer_EFB]);
//gp::XF_UpdateViewport();
SetViewport(0, 0, resolution_width_, resolution_height_);
SetDepthRange(0.0f, 1.0f);
//SetGenerationMode();
glEnable(GL_CULL_FACE);
glFrontFace(GL_CCW);
//glEnable(GL_SCISSOR_TEST);
//gp::BP_SetScissorBox();
glDisable(GL_SCISSOR_TEST);
//SetColorMask(gp::g_bp_regs.cmode0);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
//SetDepthMode();
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
//SetBlendMode(gp::g_bp_regs.cmode0, gp::g_bp_regs.cmode1, true);
//if (common::g_config->current_renderer_config().enable_wireframe) {
// glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
//} else {
// glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
//}
}
/// Initialize the FBO
void RendererOpenGL::InitFramebuffer() {
// TODO(en): This should probably be implemented with the top screen and bottom screen as
// separate framebuffers
// Init the FBOs
// -------------
glGenFramebuffers(kMaxFramebuffers, fbo_); // Generate primary framebuffer
glGenRenderbuffers(kMaxFramebuffers, fbo_rbo_); // Generate primary RBOs
glGenRenderbuffers(kMaxFramebuffers, fbo_depth_buffers_); // Generate primary depth buffer
for (int i = 0; i < kMaxFramebuffers; i++) {
// Generate color buffer storage
glBindRenderbuffer(GL_RENDERBUFFER, fbo_rbo_[i]);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, resolution_width_, resolution_height_);
// Generate depth buffer storage
glBindRenderbuffer(GL_RENDERBUFFER, fbo_depth_buffers_[i]);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT32, resolution_width_,
resolution_height_);
// Attach the buffers
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_[i]);
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
GL_RENDERBUFFER, fbo_depth_buffers_[i]);
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_RENDERBUFFER, fbo_rbo_[i]);
// Check for completeness
if (GL_FRAMEBUFFER_COMPLETE == glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER)) {
NOTICE_LOG(RENDER, "framebuffer(%d) initialized ok", i);
} else {
ERROR_LOG(RENDER, "couldn't create OpenGL frame buffer");
exit(1);
}
}
glBindFramebuffer(GL_FRAMEBUFFER, 0); // Unbind our frame buffer(s)
}
/// Blit the FBO to the OpenGL default framebuffer
void RendererOpenGL::RenderFramebuffer() {
// Render target is default framebuffer
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glViewport(0, 0, resolution_width_, resolution_height_);
// Render source is our XFB
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_[kFramebuffer_VirtualXFB]);
glReadBuffer(GL_COLOR_ATTACHMENT0);
// Blit
glBlitFramebuffer(0, 0, resolution_width_, resolution_height_, 0, 0,
render_window_->client_area_width(), render_window_->client_area_height(),
GL_COLOR_BUFFER_BIT, GL_LINEAR);
// Update the FPS count
UpdateFramerate();
// Rebind EFB
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_[kFramebuffer_EFB]);
current_frame_++;
}
/// Updates the framerate
void RendererOpenGL::UpdateFramerate() {
}
/**
* Set the emulator window to use for renderer
* @param window EmuWindow handle to emulator window to use for rendering
*/
void RendererOpenGL::SetWindow(EmuWindow* window) {
render_window_ = window;
}
/// Initialize the renderer
void RendererOpenGL::Init() {
render_window_->MakeCurrent();
glShadeModel(GL_SMOOTH);
glStencilFunc(GL_ALWAYS, 0, 0);
glBlendFunc(GL_ONE, GL_ONE);
glViewport(0, 0, resolution_width_, resolution_height_);
glClearDepth(1.0f);
glEnable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glDepthFunc(GL_LEQUAL);
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
glDisable(GL_STENCIL_TEST);
glEnable(GL_SCISSOR_TEST);
glScissor(0, 0, resolution_width_, resolution_height_);
glClearDepth(1.0f);
GLenum err = glewInit();
if (GLEW_OK != err) {
ERROR_LOG(RENDER, " Failed to initialize GLEW! Error message: \"%s\". Exiting...",
glewGetErrorString(err));
exit(-1);
}
// Initialize everything else
// --------------------------
InitFramebuffer();
NOTICE_LOG(RENDER, "GL_VERSION: %s\n", glGetString(GL_VERSION));
}
/// Shutdown the renderer
void RendererOpenGL::ShutDown() {
}
/**
* Copyright (C) 2014 Citra Emulator
*
* @file renderer_opengl.h
* @author bunnei
* @date 2014-04-05
* @brief Renderer for OpenGL 3.x
*
* @section LICENSE
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details at
* http://www.gnu.org/copyleft/gpl.html
*
* Official project repository can be found at:
* http://code.google.com/p/gekko-gc-emu/
*/
#pragma once
#include <GL/glew.h>
#include "common.h"
#include "emu_window.h"
#include "renderer_base.h"
class RendererOpenGL : virtual public RendererBase {
public:
static const int kMaxFramebuffers = 2; ///< Maximum number of framebuffers
RendererOpenGL();
~RendererOpenGL();
/// Swap buffers (render frame)
void SwapBuffers();
/**
* Blits the EFB to the external framebuffer (XFB)
* @param src_rect Source rectangle in EFB to copy
* @param dst_rect Destination rectangle in EFB to copy to
* @param dest_height Destination height in pixels
*/
void CopyToXFB(const Rect& src_rect, const Rect& dst_rect);
/**
* Clear the screen
* @param rect Screen rectangle to clear
* @param enable_color Enable color clearing
* @param enable_alpha Enable alpha clearing
* @param enable_z Enable depth clearing
* @param color Clear color
* @param z Clear depth
*/
void Clear(const Rect& rect, bool enable_color, bool enable_alpha, bool enable_z,
u32 color, u32 z);
/// Sets the renderer viewport location, width, and height
void SetViewport(int x, int y, int width, int height);
/// Sets the renderer depthrange, znear and zfar
void SetDepthRange(double znear, double zfar);
/* Sets the scissor box
* @param rect Renderer rectangle to set scissor box to
*/
void SetScissorBox(const Rect& rect);
/**
* Sets the line and point size
* @param line_width Line width to use
* @param point_size Point size to use
*/
void SetLinePointSize(f32 line_width, f32 point_size);
/**
* Set a specific render mode
* @param flag Render flags mode to enable
*/
void SetMode(kRenderMode flags);
/// Reset the full renderer API to the NULL state
void ResetRenderState();
/// Restore the full renderer API state - As the game set it
void RestoreRenderState();
/**
* Set the emulator window to use for renderer
* @param window EmuWindow handle to emulator window to use for rendering
*/
void SetWindow(EmuWindow* window);
/// Initialize the renderer
void Init();
/// Shutdown the renderer
void ShutDown();
// Framebuffer object(s)
// ---------------------
GLuint fbo_[kMaxFramebuffers]; ///< Framebuffer objects
private:
/// Initialize the FBO
void InitFramebuffer();
// Blit the FBO to the OpenGL default framebuffer
void RenderFramebuffer();
/// Updates the framerate
void UpdateFramerate();
EmuWindow* render_window_;
u32 last_mode_; ///< Last render mode
int resolution_width_;
int resolution_height_;
// Framebuffer object(s)
// ---------------------
GLuint fbo_rbo_[kMaxFramebuffers]; ///< Render buffer objects
GLuint fbo_depth_buffers_[kMaxFramebuffers]; ///< Depth buffers objects
DISALLOW_COPY_AND_ASSIGN(RendererOpenGL);
};
\ No newline at end of file
......@@ -27,7 +27,10 @@
#include "log.h"
#include "core.h"
#include "video_core.h"
#include "renderer_base.h"
#include "renderer_opengl/renderer_opengl.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// Video Core namespace
......@@ -67,16 +70,10 @@ void Start() {
/// Initialize the video core
void Init(EmuWindow* emu_window) {
g_emu_window = emu_window;
//g_renderer = new RendererGL3();
//g_renderer->SetWindow(g_emu_window);
//g_renderer->Init();
//gp::Fifo_Init();
//gp::VertexManager_Init();
//gp::VertexLoader_Init();
//gp::BP_Init();
//gp::CP_Init();
//gp::XF_Init();
g_emu_window->MakeCurrent();
g_renderer = new RendererOpenGL();
g_renderer->SetWindow(g_emu_window);
g_renderer->Init();
g_current_frame = 0;
......@@ -85,7 +82,7 @@ void Init(EmuWindow* emu_window) {
/// Shutdown the video core
void Shutdown() {
//delete g_renderer;
delete g_renderer;
}
} // namespace
......@@ -33,8 +33,19 @@
namespace VideoCore {
extern RendererBase* g_renderer; ///< Renderer plugin
extern int g_current_frame; ///< Current frame
// 3DS Video Constants
// -------------------
static const int kScreenTopWidth = 400; ///< 3DS top screen width
static const int kScreenTopHeight = 240; ///< 3DS top screen height
static const int kScreenBottomWidth = 320; ///< 3DS bottom screen width
static const int kScreenBottomHeight = 240; ///< 3DS bottom screen height
// Video core renderer
// ---------------------
extern RendererBase* g_renderer; ///< Renderer plugin
extern int g_current_frame; ///< Current frame
/// Start the video core
void Start();
......@@ -43,6 +54,6 @@ void Start();
void Init(EmuWindow* emu_window);
/// Shutdown the video core
void ShutDown();
void Shutdown();
} // namespace
......@@ -19,11 +19,13 @@
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\renderer_opengl\renderer_opengl.cpp" />
<ClCompile Include="src\utils.cpp" />
<ClCompile Include="src\video_core.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\renderer_base.h" />
<ClInclude Include="src\renderer_opengl\renderer_opengl.h" />
<ClInclude Include="src\utils.h" />
<ClInclude Include="src\video_core.h" />
</ItemGroup>
......
......@@ -3,13 +3,24 @@
<ItemGroup>
<ClCompile Include="src\video_core.cpp" />
<ClCompile Include="src\utils.cpp" />
<ClCompile Include="src\renderer_opengl\renderer_opengl.cpp">
<Filter>renderer_opengl</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\renderer_base.h" />
<ClInclude Include="src\video_core.h" />
<ClInclude Include="src\utils.h" />
<ClInclude Include="src\renderer_opengl\renderer_opengl.h">
<Filter>renderer_opengl</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Text Include="CMakeLists.txt" />
</ItemGroup>
<ItemGroup>
<Filter Include="renderer_opengl">
<UniqueIdentifier>{e0245557-dbd4-423e-9399-513d5e99f1e4}</UniqueIdentifier>
</Filter>
</ItemGroup>
</Project>
\ No newline at end of file
......@@ -12,7 +12,7 @@
<StructMemberAlignment>16Bytes</StructMemberAlignment>
<FunctionLevelLinking>true</FunctionLevelLinking>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<AdditionalIncludeDirectories>$(SolutionDir)src\common\src;$(SolutionDir)src\core\src;$(SolutionDir)src\citra\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)src\common\src;$(SolutionDir)src\core\src;$(SolutionDir)src\video_core\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>
</PreprocessorDefinitions>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment