diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/citra_qt/debugger/graphics_vertex_shader.cpp | 4 | ||||
-rw-r--r-- | src/citra_qt/main.cpp | 65 | ||||
-rw-r--r-- | src/citra_qt/main.h | 2 | ||||
-rw-r--r-- | src/common/common_funcs.h | 10 | ||||
-rw-r--r-- | src/core/core.cpp | 3 | ||||
-rw-r--r-- | src/core/core.h | 2 | ||||
-rw-r--r-- | src/core/hle/service/gsp_gpu.cpp | 8 | ||||
-rw-r--r-- | src/core/hle/service/y2r_u.cpp | 2 | ||||
-rw-r--r-- | src/core/hw/gpu.cpp | 10 | ||||
-rw-r--r-- | src/core/loader/loader.cpp | 6 | ||||
-rw-r--r-- | src/core/system.cpp | 8 | ||||
-rw-r--r-- | src/core/system.h | 9 | ||||
-rw-r--r-- | src/video_core/command_processor.cpp | 10 | ||||
-rw-r--r-- | src/video_core/debug_utils/debug_utils.cpp | 2 | ||||
-rw-r--r-- | src/video_core/renderer_base.h | 20 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.cpp | 8 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.h | 2 | ||||
-rw-r--r-- | src/video_core/shader/shader.h | 8 | ||||
-rw-r--r-- | src/video_core/video_core.cpp | 12 | ||||
-rw-r--r-- | src/video_core/video_core.h | 2 |
20 files changed, 129 insertions, 64 deletions
diff --git a/src/citra_qt/debugger/graphics_vertex_shader.cpp b/src/citra_qt/debugger/graphics_vertex_shader.cpp index a11c61667..4b676f1b1 100644 --- a/src/citra_qt/debugger/graphics_vertex_shader.cpp +++ b/src/citra_qt/debugger/graphics_vertex_shader.cpp @@ -498,8 +498,8 @@ void GraphicsVertexShaderWidget::Reload(bool replace_vertex_data, void* vertex_d // Reload widget state for (int attr = 0; attr < num_attributes; ++attr) { unsigned source_attr = shader_config.input_register_map.GetRegisterForAttribute(attr); - input_data_mapping[source_attr]->setText(QString("-> v%1").arg(attr)); - input_data_container[source_attr]->setVisible(true); + input_data_mapping[attr]->setText(QString("-> v%1").arg(source_attr)); + input_data_container[attr]->setVisible(true); } // Only show input attributes which are used as input to the shader for (unsigned int attr = num_attributes; attr < 16; ++attr) { diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 1854f442a..57adbc136 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -249,22 +249,73 @@ void GMainWindow::OnDisplayTitleBars(bool show) } } -void GMainWindow::BootGame(const std::string& filename) { - LOG_INFO(Frontend, "Citra starting..."); - +bool GMainWindow::InitializeSystem() { // Shutdown previous session if the emu thread is still active... if (emu_thread != nullptr) ShutdownGame(); // Initialize the core emulation - System::Init(render_window); + System::Result system_result = System::Init(render_window); + if (System::Result::Success != system_result) { + switch (system_result) { + case System::Result::ErrorInitVideoCore: + QMessageBox::critical(this, tr("Error while starting Citra!"), + tr("Failed to initialize the video core!\n\n" + "Please ensure that your GPU supports OpenGL 3.3 and that you have the latest graphics driver.")); + break; + + default: + QMessageBox::critical(this, tr("Error while starting Citra!"), + tr("Unknown error (please check the log)!")); + break; + } + return false; + } + return true; +} - // Load the game - if (Loader::ResultStatus::Success != Loader::LoadFile(filename)) { +bool GMainWindow::LoadROM(const std::string& filename) { + Loader::ResultStatus result = Loader::LoadFile(filename); + if (Loader::ResultStatus::Success != result) { LOG_CRITICAL(Frontend, "Failed to load ROM!"); System::Shutdown(); - return; + + switch (result) { + case Loader::ResultStatus::ErrorEncrypted: { + // Build the MessageBox ourselves to have clickable link + QMessageBox popup_error; + popup_error.setTextFormat(Qt::RichText); + popup_error.setWindowTitle(tr("Error while loading ROM!")); + popup_error.setText(tr("The game that you are trying to load must be decrypted before being used with Citra.<br/><br/>" + "For more information on dumping and decrypting games, please see: <a href='https://citra-emu.org/wiki/Dumping-Game-Cartridges'>https://citra-emu.org/wiki/Dumping-Game-Cartridges</a>")); + popup_error.setIcon(QMessageBox::Critical); + popup_error.exec(); + break; + } + case Loader::ResultStatus::ErrorInvalidFormat: + QMessageBox::critical(this, tr("Error while loading ROM!"), + tr("The ROM format is not supported.")); + break; + case Loader::ResultStatus::Error: + + default: + QMessageBox::critical(this, tr("Error while loading ROM!"), + tr("Unknown error!")); + break; + } + return false; } + return true; +} + +void GMainWindow::BootGame(const std::string& filename) { + LOG_INFO(Frontend, "Citra starting..."); + + if (!InitializeSystem()) + return; + + if (!LoadROM(filename)) + return; // Create and start the emulation thread emu_thread = Common::make_unique<EmuThread>(render_window); diff --git a/src/citra_qt/main.h b/src/citra_qt/main.h index 8c195f816..945aea0cd 100644 --- a/src/citra_qt/main.h +++ b/src/citra_qt/main.h @@ -59,6 +59,8 @@ signals: void EmulationStopping(); private: + bool InitializeSystem(); + bool LoadROM(const std::string& filename); void BootGame(const std::string& filename); void ShutdownGame(); diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h index ed20c3629..aa6aff7b9 100644 --- a/src/common/common_funcs.h +++ b/src/common/common_funcs.h @@ -18,19 +18,11 @@ #define INSERT_PADDING_BYTES(num_bytes) u8 CONCAT2(pad, __LINE__)[(num_bytes)] #define INSERT_PADDING_WORDS(num_words) u32 CONCAT2(pad, __LINE__)[(num_words)] +// Inlining #ifdef _WIN32 - // Alignment #define FORCE_INLINE __forceinline - #define MEMORY_ALIGNED16(x) __declspec(align(16)) x - #define MEMORY_ALIGNED32(x) __declspec(align(32)) x - #define MEMORY_ALIGNED64(x) __declspec(align(64)) x - #define MEMORY_ALIGNED128(x) __declspec(align(128)) x #else #define FORCE_INLINE inline __attribute__((always_inline)) - #define MEMORY_ALIGNED16(x) __attribute__((aligned(16))) x - #define MEMORY_ALIGNED32(x) __attribute__((aligned(32))) x - #define MEMORY_ALIGNED64(x) __attribute__((aligned(64))) x - #define MEMORY_ALIGNED128(x) __attribute__((aligned(128))) x #endif #ifndef _MSC_VER diff --git a/src/core/core.cpp b/src/core/core.cpp index 453c7162d..84d6c392e 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -73,12 +73,11 @@ void Stop() { } /// Initialize the core -int Init() { +void Init() { g_sys_core = Common::make_unique<ARM_DynCom>(USER32MODE); g_app_core = Common::make_unique<ARM_DynCom>(USER32MODE); LOG_DEBUG(Core, "Initialized OK"); - return 0; } void Shutdown() { diff --git a/src/core/core.h b/src/core/core.h index 453e0a5f0..ad26dca3f 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -52,7 +52,7 @@ void Halt(const char *msg); void Stop(); /// Initialize the core -int Init(); +void Init(); /// Shutdown the core void Shutdown(); diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp index 5838b6d71..3d705821d 100644 --- a/src/core/hle/service/gsp_gpu.cpp +++ b/src/core/hle/service/gsp_gpu.cpp @@ -275,7 +275,7 @@ static void FlushDataCache(Service::Interface* self) { u32 size = cmd_buff[2]; u32 process = cmd_buff[4]; - VideoCore::g_renderer->rasterizer->InvalidateRegion(Memory::VirtualToPhysicalAddress(address), size); + VideoCore::g_renderer->Rasterizer()->InvalidateRegion(Memory::VirtualToPhysicalAddress(address), size); // TODO(purpasmart96): Verify return header on HW @@ -365,7 +365,7 @@ static void ExecuteCommand(const Command& command, u32 thread_id) { // GX request DMA - typically used for copying memory from GSP heap to VRAM case CommandId::REQUEST_DMA: - VideoCore::g_renderer->rasterizer->FlushRegion(Memory::VirtualToPhysicalAddress(command.dma_request.source_address), + VideoCore::g_renderer->Rasterizer()->FlushRegion(Memory::VirtualToPhysicalAddress(command.dma_request.source_address), command.dma_request.size); memcpy(Memory::GetPointer(command.dma_request.dest_address), @@ -373,7 +373,7 @@ static void ExecuteCommand(const Command& command, u32 thread_id) { command.dma_request.size); SignalInterrupt(InterruptId::DMA); - VideoCore::g_renderer->rasterizer->InvalidateRegion(Memory::VirtualToPhysicalAddress(command.dma_request.dest_address), + VideoCore::g_renderer->Rasterizer()->InvalidateRegion(Memory::VirtualToPhysicalAddress(command.dma_request.dest_address), command.dma_request.size); break; @@ -467,7 +467,7 @@ static void ExecuteCommand(const Command& command, u32 thread_id) { if (region.size == 0) break; - VideoCore::g_renderer->rasterizer->InvalidateRegion( + VideoCore::g_renderer->Rasterizer()->InvalidateRegion( Memory::VirtualToPhysicalAddress(region.address), region.size); } break; diff --git a/src/core/hle/service/y2r_u.cpp b/src/core/hle/service/y2r_u.cpp index bbead9344..a495441a4 100644 --- a/src/core/hle/service/y2r_u.cpp +++ b/src/core/hle/service/y2r_u.cpp @@ -267,7 +267,7 @@ static void StartConversion(Service::Interface* self) { // dst_image_size would seem to be perfect for this, but it doesn't include the gap :( u32 total_output_size = conversion.input_lines * (conversion.dst.transfer_unit + conversion.dst.gap); - VideoCore::g_renderer->rasterizer->InvalidateRegion( + VideoCore::g_renderer->Rasterizer()->InvalidateRegion( Memory::VirtualToPhysicalAddress(conversion.dst.address), total_output_size); LOG_DEBUG(Service_Y2R, "called"); diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp index 5312baa83..7e2f9cdfa 100644 --- a/src/core/hw/gpu.cpp +++ b/src/core/hw/gpu.cpp @@ -140,7 +140,7 @@ inline void Write(u32 addr, const T data) { GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PSC1); } - VideoCore::g_renderer->rasterizer->InvalidateRegion(config.GetStartAddress(), config.GetEndAddress() - config.GetStartAddress()); + VideoCore::g_renderer->Rasterizer()->InvalidateRegion(config.GetStartAddress(), config.GetEndAddress() - config.GetStartAddress()); } // Reset "trigger" flag and set the "finish" flag @@ -171,7 +171,7 @@ inline void Write(u32 addr, const T data) { u32 output_gap = config.texture_copy.output_gap * 16; size_t contiguous_input_size = config.texture_copy.size / input_width * (input_width + input_gap); - VideoCore::g_renderer->rasterizer->FlushRegion(config.GetPhysicalInputAddress(), contiguous_input_size); + VideoCore::g_renderer->Rasterizer()->FlushRegion(config.GetPhysicalInputAddress(), contiguous_input_size); u32 remaining_size = config.texture_copy.size; u32 remaining_input = input_width; @@ -204,7 +204,7 @@ inline void Write(u32 addr, const T data) { config.flags); size_t contiguous_output_size = config.texture_copy.size / output_width * (output_width + output_gap); - VideoCore::g_renderer->rasterizer->InvalidateRegion(config.GetPhysicalOutputAddress(), contiguous_output_size); + VideoCore::g_renderer->Rasterizer()->InvalidateRegion(config.GetPhysicalOutputAddress(), contiguous_output_size); GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PPF); break; @@ -231,7 +231,7 @@ inline void Write(u32 addr, const T data) { u32 input_size = config.input_width * config.input_height * GPU::Regs::BytesPerPixel(config.input_format); u32 output_size = output_width * output_height * GPU::Regs::BytesPerPixel(config.output_format); - VideoCore::g_renderer->rasterizer->FlushRegion(config.GetPhysicalInputAddress(), input_size); + VideoCore::g_renderer->Rasterizer()->FlushRegion(config.GetPhysicalInputAddress(), input_size); for (u32 y = 0; y < output_height; ++y) { for (u32 x = 0; x < output_width; ++x) { @@ -338,7 +338,7 @@ inline void Write(u32 addr, const T data) { g_regs.display_transfer_config.trigger = 0; GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PPF); - VideoCore::g_renderer->rasterizer->InvalidateRegion(config.GetPhysicalOutputAddress(), output_size); + VideoCore::g_renderer->Rasterizer()->InvalidateRegion(config.GetPhysicalOutputAddress(), output_size); } break; } diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index 6b88169e1..b1907cd55 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp @@ -137,11 +137,11 @@ ResultStatus LoadFile(const std::string& filename) { AppLoader_NCCH app_loader(std::move(file), filename); // Load application and RomFS - if (ResultStatus::Success == app_loader.Load()) { + ResultStatus result = app_loader.Load(); + if (ResultStatus::Success == result) { Service::FS::RegisterArchiveType(Common::make_unique<FileSys::ArchiveFactory_RomFS>(app_loader), Service::FS::ArchiveIdCode::RomFS); - return ResultStatus::Success; } - break; + return result; } // CIA file format... diff --git a/src/core/system.cpp b/src/core/system.cpp index b62ebf69e..4a4757af3 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -17,16 +17,20 @@ namespace System { -void Init(EmuWindow* emu_window) { +Result Init(EmuWindow* emu_window) { Core::Init(); CoreTiming::Init(); Memory::Init(); HW::Init(); Kernel::Init(); HLE::Init(); - VideoCore::Init(emu_window); + if (!VideoCore::Init(emu_window)) { + return Result::ErrorInitVideoCore; + } AudioCore::Init(); GDBStub::Init(); + + return Result::Success; } void Shutdown() { diff --git a/src/core/system.h b/src/core/system.h index 59a75ca12..a4a627ea9 100644 --- a/src/core/system.h +++ b/src/core/system.h @@ -8,7 +8,14 @@ class EmuWindow; namespace System { -void Init(EmuWindow* emu_window); +enum class Result { + Success, ///< Everything is fine + Error, ///< Something went wrong (no module specified) + ErrorInitCore, ///< Something went wrong during core init + ErrorInitVideoCore, ///< Something went wrong during video core init +}; + +Result Init(EmuWindow* emu_window); void Shutdown(); } diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp index 2f92be661..2274dfa66 100644 --- a/src/video_core/command_processor.cpp +++ b/src/video_core/command_processor.cpp @@ -142,7 +142,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { // Send to renderer using Pica::Shader::OutputVertex; auto AddTriangle = [](const OutputVertex& v0, const OutputVertex& v1, const OutputVertex& v2) { - VideoCore::g_renderer->rasterizer->AddTriangle(v0, v1, v2); + VideoCore::g_renderer->Rasterizer()->AddTriangle(v0, v1, v2); }; g_state.immediate.primitive_assembler.SubmitVertex(output, AddTriangle); @@ -155,7 +155,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { case PICA_REG_INDEX(gpu_mode): if (regs.gpu_mode == Regs::GPUMode::Configuring && regs.vs_default_attributes_setup.index == 15) { // Draw immediate mode triangles when GPU Mode is set to GPUMode::Configuring - VideoCore::g_renderer->rasterizer->DrawTriangles(); + VideoCore::g_renderer->Rasterizer()->DrawTriangles(); } break; @@ -396,7 +396,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { using Pica::Shader::OutputVertex; auto AddTriangle = []( const OutputVertex& v0, const OutputVertex& v1, const OutputVertex& v2) { - VideoCore::g_renderer->rasterizer->AddTriangle(v0, v1, v2); + VideoCore::g_renderer->Rasterizer()->AddTriangle(v0, v1, v2); }; primitive_assembler.SubmitVertex(output, AddTriangle); @@ -407,7 +407,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { range.second, range.first); } - VideoCore::g_renderer->rasterizer->DrawTriangles(); + VideoCore::g_renderer->Rasterizer()->DrawTriangles(); #if PICA_DUMP_GEOMETRY geometry_dumper.Dump(); @@ -542,7 +542,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { break; } - VideoCore::g_renderer->rasterizer->NotifyPicaRegisterChanged(id); + VideoCore::g_renderer->Rasterizer()->NotifyPicaRegisterChanged(id); if (g_debug_context) g_debug_context->OnEvent(DebugContext::Event::PicaCommandProcessed, reinterpret_cast<void*>(&id)); diff --git a/src/video_core/debug_utils/debug_utils.cpp b/src/video_core/debug_utils/debug_utils.cpp index 6e21caa78..271e81ca1 100644 --- a/src/video_core/debug_utils/debug_utils.cpp +++ b/src/video_core/debug_utils/debug_utils.cpp @@ -48,7 +48,7 @@ void DebugContext::OnEvent(Event event, void* data) { std::unique_lock<std::mutex> lock(breakpoint_mutex); // Commit the hardware renderer's framebuffer so it will show on debug widgets - VideoCore::g_renderer->rasterizer->FlushFramebuffer(); + VideoCore::g_renderer->Rasterizer()->FlushFramebuffer(); // TODO: Should stop the CPU thread here once we multithread emulation. diff --git a/src/video_core/renderer_base.h b/src/video_core/renderer_base.h index 506bff815..f68091cc8 100644 --- a/src/video_core/renderer_base.h +++ b/src/video_core/renderer_base.h @@ -22,9 +22,6 @@ public: kFramebuffer_Texture }; - RendererBase() : m_current_fps(0), m_current_frame(0) { - } - virtual ~RendererBase() { } @@ -38,7 +35,7 @@ public: virtual void SetWindow(EmuWindow* window) = 0; /// Initialize the renderer - virtual void Init() = 0; + virtual bool Init() = 0; /// Shutdown the renderer virtual void ShutDown() = 0; @@ -46,21 +43,24 @@ public: // Getter/setter functions: // ------------------------ - f32 GetCurrentframe() const { + f32 GetCurrentFPS() const { return m_current_fps; } - int current_frame() const { + int GetCurrentFrame() const { return m_current_frame; } - void RefreshRasterizerSetting(); + VideoCore::RasterizerInterface* Rasterizer() const { + return rasterizer.get(); + } - std::unique_ptr<VideoCore::RasterizerInterface> rasterizer; + void RefreshRasterizerSetting(); protected: - f32 m_current_fps; ///< Current framerate, should be set by the renderer - int m_current_frame; ///< Current frame, should be set by the renderer + std::unique_ptr<VideoCore::RasterizerInterface> rasterizer; + f32 m_current_fps = 0.0f; ///< Current framerate, should be set by the renderer + int m_current_frame = 0; ///< Current frame, should be set by the renderer private: bool opengl_rasterizer_active = false; diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index ca3a6a6b4..11c4d0daf 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -445,7 +445,7 @@ static void DebugHandler(GLenum source, GLenum type, GLuint id, GLenum severity, } /// Initialize the renderer -void RendererOpenGL::Init() { +bool RendererOpenGL::Init() { render_window->MakeCurrent(); // TODO: Make frontends initialize this, so they can use gladLoadGLLoader with their own loaders @@ -462,9 +462,15 @@ void RendererOpenGL::Init() { LOG_INFO(Render_OpenGL, "GL_VERSION: %s", glGetString(GL_VERSION)); LOG_INFO(Render_OpenGL, "GL_VENDOR: %s", glGetString(GL_VENDOR)); LOG_INFO(Render_OpenGL, "GL_RENDERER: %s", glGetString(GL_RENDERER)); + if (!GLAD_GL_VERSION_3_3) { + return false; + } + InitOpenGLObjects(); RefreshRasterizerSetting(); + + return true; } /// Shutdown the renderer diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h index b42df7654..fe4d142a5 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.h +++ b/src/video_core/renderer_opengl/renderer_opengl.h @@ -31,7 +31,7 @@ public: void SetWindow(EmuWindow* window) override; /// Initialize the renderer - void Init() override; + bool Init() override; /// Shutdown the renderer void ShutDown() override; diff --git a/src/video_core/shader/shader.h b/src/video_core/shader/shader.h index 1be4e3734..7af8f1fa1 100644 --- a/src/video_core/shader/shader.h +++ b/src/video_core/shader/shader.h @@ -82,7 +82,7 @@ struct ShaderSetup { struct { // The float uniforms are accessed by the shader JIT using SSE instructions, and are // therefore required to be 16-byte aligned. - Math::Vec4<float24> MEMORY_ALIGNED16(f[96]); + alignas(16) Math::Vec4<float24> f[96]; std::array<bool, 16> b; std::array<Math::Vec4<u8>, 4> i; @@ -276,9 +276,9 @@ struct UnitState { struct Registers { // The registers are accessed by the shader JIT using SSE instructions, and are therefore // required to be 16-byte aligned. - Math::Vec4<float24> MEMORY_ALIGNED16(input[16]); - Math::Vec4<float24> MEMORY_ALIGNED16(output[16]); - Math::Vec4<float24> MEMORY_ALIGNED16(temporary[16]); + alignas(16) Math::Vec4<float24> input[16]; + alignas(16) Math::Vec4<float24> output[16]; + alignas(16) Math::Vec4<float24> temporary[16]; } registers; static_assert(std::is_pod<Registers>::value, "Structure is not POD"); diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp index 912db91a4..ee5e50df1 100644 --- a/src/video_core/video_core.cpp +++ b/src/video_core/video_core.cpp @@ -28,15 +28,19 @@ std::atomic<bool> g_hw_renderer_enabled; std::atomic<bool> g_shader_jit_enabled; /// Initialize the video core -void Init(EmuWindow* emu_window) { +bool Init(EmuWindow* emu_window) { Pica::Init(); g_emu_window = emu_window; g_renderer = Common::make_unique<RendererOpenGL>(); g_renderer->SetWindow(g_emu_window); - g_renderer->Init(); - - LOG_DEBUG(Render, "initialized OK"); + if (g_renderer->Init()) { + LOG_DEBUG(Render, "initialized OK"); + } else { + LOG_ERROR(Render, "initialization failed !"); + return false; + } + return true; } /// Shutdown the video core diff --git a/src/video_core/video_core.h b/src/video_core/video_core.h index accb0a4eb..bca67fb8c 100644 --- a/src/video_core/video_core.h +++ b/src/video_core/video_core.h @@ -41,7 +41,7 @@ extern std::atomic<bool> g_shader_jit_enabled; void Start(); /// Initialize the video core -void Init(EmuWindow* emu_window); +bool Init(EmuWindow* emu_window); /// Shutdown the video core void Shutdown(); |