diff options
Diffstat (limited to 'src')
45 files changed, 998 insertions, 730 deletions
diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt index 51a574629..bbf6ae001 100644 --- a/src/citra_qt/CMakeLists.txt +++ b/src/citra_qt/CMakeLists.txt | |||
| @@ -24,6 +24,7 @@ set(SRCS | |||
| 24 | hotkeys.cpp | 24 | hotkeys.cpp |
| 25 | main.cpp | 25 | main.cpp |
| 26 | citra-qt.rc | 26 | citra-qt.rc |
| 27 | Info.plist | ||
| 27 | ) | 28 | ) |
| 28 | 29 | ||
| 29 | set(HEADERS | 30 | set(HEADERS |
| @@ -71,7 +72,10 @@ else() | |||
| 71 | endif() | 72 | endif() |
| 72 | 73 | ||
| 73 | if (APPLE) | 74 | if (APPLE) |
| 74 | add_executable(citra-qt MACOSX_BUNDLE ${SRCS} ${HEADERS} ${UI_HDRS}) | 75 | set(MACOSX_ICON "../../dist/citra.icns") |
| 76 | set_source_files_properties(${MACOSX_ICON} PROPERTIES MACOSX_PACKAGE_LOCATION Resources) | ||
| 77 | add_executable(citra-qt MACOSX_BUNDLE ${SRCS} ${HEADERS} ${UI_HDRS} ${MACOSX_ICON}) | ||
| 78 | set_target_properties(citra-qt PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist) | ||
| 75 | else() | 79 | else() |
| 76 | add_executable(citra-qt ${SRCS} ${HEADERS} ${UI_HDRS}) | 80 | add_executable(citra-qt ${SRCS} ${HEADERS} ${UI_HDRS}) |
| 77 | endif() | 81 | endif() |
diff --git a/src/citra_qt/Info.plist b/src/citra_qt/Info.plist new file mode 100644 index 000000000..4c89e128b --- /dev/null +++ b/src/citra_qt/Info.plist | |||
| @@ -0,0 +1,40 @@ | |||
| 1 | <?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||
| 3 | <plist version="1.0"> | ||
| 4 | <dict> | ||
| 5 | <key>CFBundleDevelopmentRegion</key> | ||
| 6 | <string>English</string> | ||
| 7 | <key>CFBundleExecutable</key> | ||
| 8 | <string>$(EXECUTABLE_NAME)</string> | ||
| 9 | <key>CFBundleGetInfoString</key> | ||
| 10 | <string></string> | ||
| 11 | <key>CFBundleIconFile</key> | ||
| 12 | <string>citra.icns</string> | ||
| 13 | <key>CFBundleIdentifier</key> | ||
| 14 | <string>com.citra-emu.citra</string> | ||
| 15 | <key>CFBundleInfoDictionaryVersion</key> | ||
| 16 | <string>6.0</string> | ||
| 17 | <key>CFBundleLongVersionString</key> | ||
| 18 | <string></string> | ||
| 19 | <key>CFBundleName</key> | ||
| 20 | <string>Citra</string> | ||
| 21 | <key>CFBundlePackageType</key> | ||
| 22 | <string>APPL</string> | ||
| 23 | <key>CFBundleShortVersionString</key> | ||
| 24 | <string></string> | ||
| 25 | <key>CFBundleSignature</key> | ||
| 26 | <string>????</string> | ||
| 27 | <key>CFBundleVersion</key> | ||
| 28 | <string></string> | ||
| 29 | <key>CSResourcesFileMapped</key> | ||
| 30 | <true/> | ||
| 31 | <key>LSRequiresCarbon</key> | ||
| 32 | <true/> | ||
| 33 | <key>NSHumanReadableCopyright</key> | ||
| 34 | <string></string> | ||
| 35 | <key>NSPrincipalClass</key> | ||
| 36 | <string>NSApplication</string> | ||
| 37 | <key>NSHighResolutionCapable</key> | ||
| 38 | <string>True</string> | ||
| 39 | </dict> | ||
| 40 | </plist> | ||
diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp index b19b367e1..8e60b9cad 100644 --- a/src/citra_qt/bootmanager.cpp +++ b/src/citra_qt/bootmanager.cpp | |||
| @@ -181,16 +181,9 @@ void GRenderWindow::PollEvents() { | |||
| 181 | void GRenderWindow::OnFramebufferSizeChanged() | 181 | void GRenderWindow::OnFramebufferSizeChanged() |
| 182 | { | 182 | { |
| 183 | // Screen changes potentially incur a change in screen DPI, hence we should update the framebuffer size | 183 | // Screen changes potentially incur a change in screen DPI, hence we should update the framebuffer size |
| 184 | #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) | 184 | qreal pixelRatio = windowPixelRatio(); |
| 185 | // windowHandle() might not be accessible until the window is displayed to screen. | 185 | unsigned width = child->QPaintDevice::width() * pixelRatio; |
| 186 | auto pixel_ratio = windowHandle() ? (windowHandle()->screen()->devicePixelRatio()) : 1.0; | 186 | unsigned height = child->QPaintDevice::height() * pixelRatio; |
| 187 | |||
| 188 | unsigned width = child->QPaintDevice::width() * pixel_ratio; | ||
| 189 | unsigned height = child->QPaintDevice::height() * pixel_ratio; | ||
| 190 | #else | ||
| 191 | unsigned width = child->QPaintDevice::width(); | ||
| 192 | unsigned height = child->QPaintDevice::height(); | ||
| 193 | #endif | ||
| 194 | 187 | ||
| 195 | NotifyFramebufferLayoutChanged(EmuWindow::FramebufferLayout::DefaultScreenLayout(width, height)); | 188 | NotifyFramebufferLayoutChanged(EmuWindow::FramebufferLayout::DefaultScreenLayout(width, height)); |
| 196 | } | 189 | } |
| @@ -223,6 +216,16 @@ QByteArray GRenderWindow::saveGeometry() | |||
| 223 | return geometry; | 216 | return geometry; |
| 224 | } | 217 | } |
| 225 | 218 | ||
| 219 | qreal GRenderWindow::windowPixelRatio() | ||
| 220 | { | ||
| 221 | #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) | ||
| 222 | // windowHandle() might not be accessible until the window is displayed to screen. | ||
| 223 | return windowHandle() ? windowHandle()->screen()->devicePixelRatio() : 1.0f; | ||
| 224 | #else | ||
| 225 | return 1.0f; | ||
| 226 | #endif | ||
| 227 | } | ||
| 228 | |||
| 226 | void GRenderWindow::closeEvent(QCloseEvent* event) { | 229 | void GRenderWindow::closeEvent(QCloseEvent* event) { |
| 227 | emit Closed(); | 230 | emit Closed(); |
| 228 | QWidget::closeEvent(event); | 231 | QWidget::closeEvent(event); |
| @@ -243,14 +246,18 @@ void GRenderWindow::mousePressEvent(QMouseEvent *event) | |||
| 243 | if (event->button() == Qt::LeftButton) | 246 | if (event->button() == Qt::LeftButton) |
| 244 | { | 247 | { |
| 245 | auto pos = event->pos(); | 248 | auto pos = event->pos(); |
| 246 | this->TouchPressed(static_cast<unsigned>(pos.x()), static_cast<unsigned>(pos.y())); | 249 | qreal pixelRatio = windowPixelRatio(); |
| 250 | this->TouchPressed(static_cast<unsigned>(pos.x() * pixelRatio), | ||
| 251 | static_cast<unsigned>(pos.y() * pixelRatio)); | ||
| 247 | } | 252 | } |
| 248 | } | 253 | } |
| 249 | 254 | ||
| 250 | void GRenderWindow::mouseMoveEvent(QMouseEvent *event) | 255 | void GRenderWindow::mouseMoveEvent(QMouseEvent *event) |
| 251 | { | 256 | { |
| 252 | auto pos = event->pos(); | 257 | auto pos = event->pos(); |
| 253 | this->TouchMoved(static_cast<unsigned>(std::max(pos.x(), 0)), static_cast<unsigned>(std::max(pos.y(), 0))); | 258 | qreal pixelRatio = windowPixelRatio(); |
| 259 | this->TouchMoved(std::max(static_cast<unsigned>(pos.x() * pixelRatio), 0u), | ||
| 260 | std::max(static_cast<unsigned>(pos.y() * pixelRatio), 0u)); | ||
| 254 | } | 261 | } |
| 255 | 262 | ||
| 256 | void GRenderWindow::mouseReleaseEvent(QMouseEvent *event) | 263 | void GRenderWindow::mouseReleaseEvent(QMouseEvent *event) |
diff --git a/src/citra_qt/bootmanager.h b/src/citra_qt/bootmanager.h index 0a9d263b8..0dcf3e5eb 100644 --- a/src/citra_qt/bootmanager.h +++ b/src/citra_qt/bootmanager.h | |||
| @@ -111,6 +111,8 @@ public: | |||
| 111 | void restoreGeometry(const QByteArray& geometry); // overridden | 111 | void restoreGeometry(const QByteArray& geometry); // overridden |
| 112 | QByteArray saveGeometry(); // overridden | 112 | QByteArray saveGeometry(); // overridden |
| 113 | 113 | ||
| 114 | qreal windowPixelRatio(); | ||
| 115 | |||
| 114 | void closeEvent(QCloseEvent* event) override; | 116 | void closeEvent(QCloseEvent* event) override; |
| 115 | 117 | ||
| 116 | void keyPressEvent(QKeyEvent* event) override; | 118 | void keyPressEvent(QKeyEvent* event) override; |
diff --git a/src/citra_qt/debugger/graphics_vertex_shader.cpp b/src/citra_qt/debugger/graphics_vertex_shader.cpp index f915d2bab..a5a5fe6b0 100644 --- a/src/citra_qt/debugger/graphics_vertex_shader.cpp +++ b/src/citra_qt/debugger/graphics_vertex_shader.cpp | |||
| @@ -294,16 +294,16 @@ QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) con | |||
| 294 | { | 294 | { |
| 295 | // Highlight current instruction | 295 | // Highlight current instruction |
| 296 | int current_record_index = par->cycle_index->value(); | 296 | int current_record_index = par->cycle_index->value(); |
| 297 | if (current_record_index < par->debug_data.records.size()) { | 297 | if (current_record_index < static_cast<int>(par->debug_data.records.size())) { |
| 298 | const auto& current_record = par->debug_data.records[current_record_index]; | 298 | const auto& current_record = par->debug_data.records[current_record_index]; |
| 299 | if (index.row() == current_record.instruction_offset) { | 299 | if (index.row() == static_cast<int>(current_record.instruction_offset)) { |
| 300 | return QColor(255, 255, 63); | 300 | return QColor(255, 255, 63); |
| 301 | } | 301 | } |
| 302 | } | 302 | } |
| 303 | 303 | ||
| 304 | // Use a grey background for instructions which have no debug data associated to them | 304 | // Use a grey background for instructions which have no debug data associated to them |
| 305 | for (const auto& record : par->debug_data.records) | 305 | for (const auto& record : par->debug_data.records) |
| 306 | if (index.row() == record.instruction_offset) | 306 | if (index.row() == static_cast<int>(record.instruction_offset)) |
| 307 | return QVariant(); | 307 | return QVariant(); |
| 308 | 308 | ||
| 309 | return QBrush(QColor(192, 192, 192)); | 309 | return QBrush(QColor(192, 192, 192)); |
| @@ -494,7 +494,7 @@ void GraphicsVertexShaderWidget::Reload(bool replace_vertex_data, void* vertex_d | |||
| 494 | debug_data = Pica::Shader::ProduceDebugInfo(input_vertex, num_attributes, shader_config, shader_setup); | 494 | debug_data = Pica::Shader::ProduceDebugInfo(input_vertex, num_attributes, shader_config, shader_setup); |
| 495 | 495 | ||
| 496 | // Reload widget state | 496 | // Reload widget state |
| 497 | for (unsigned int attr = 0; attr < num_attributes; ++attr) { | 497 | for (int attr = 0; attr < num_attributes; ++attr) { |
| 498 | unsigned source_attr = shader_config.input_register_map.GetRegisterForAttribute(attr); | 498 | unsigned source_attr = shader_config.input_register_map.GetRegisterForAttribute(attr); |
| 499 | input_data_mapping[source_attr]->setText(QString("-> v%1").arg(attr)); | 499 | input_data_mapping[source_attr]->setText(QString("-> v%1").arg(attr)); |
| 500 | input_data_container[source_attr]->setVisible(true); | 500 | input_data_container[source_attr]->setVisible(true); |
diff --git a/src/citra_qt/game_list.cpp b/src/citra_qt/game_list.cpp index dade3c212..e925f08a7 100644 --- a/src/citra_qt/game_list.cpp +++ b/src/citra_qt/game_list.cpp | |||
| @@ -80,7 +80,7 @@ void GameList::DonePopulating() | |||
| 80 | void GameList::PopulateAsync(const QString& dir_path, bool deep_scan) | 80 | void GameList::PopulateAsync(const QString& dir_path, bool deep_scan) |
| 81 | { | 81 | { |
| 82 | if (!FileUtil::Exists(dir_path.toStdString()) || !FileUtil::IsDirectory(dir_path.toStdString())) { | 82 | if (!FileUtil::Exists(dir_path.toStdString()) || !FileUtil::IsDirectory(dir_path.toStdString())) { |
| 83 | LOG_ERROR(Frontend, "Could not find game list folder at %s", dir_path.toLatin1().data()); | 83 | LOG_ERROR(Frontend, "Could not find game list folder at %s", dir_path.toLocal8Bit().data()); |
| 84 | return; | 84 | return; |
| 85 | } | 85 | } |
| 86 | 86 | ||
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index e5ed01a11..d6c27f0df 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp | |||
| @@ -247,7 +247,7 @@ void GMainWindow::OnDisplayTitleBars(bool show) | |||
| 247 | } | 247 | } |
| 248 | 248 | ||
| 249 | void GMainWindow::BootGame(const std::string& filename) { | 249 | void GMainWindow::BootGame(const std::string& filename) { |
| 250 | LOG_INFO(Frontend, "Citra starting...\n"); | 250 | LOG_INFO(Frontend, "Citra starting..."); |
| 251 | 251 | ||
| 252 | // Shutdown previous session if the emu thread is still active... | 252 | // Shutdown previous session if the emu thread is still active... |
| 253 | if (emu_thread != nullptr) | 253 | if (emu_thread != nullptr) |
| @@ -362,7 +362,7 @@ void GMainWindow::UpdateRecentFiles() { | |||
| 362 | } | 362 | } |
| 363 | 363 | ||
| 364 | void GMainWindow::OnGameListLoadFile(QString game_path) { | 364 | void GMainWindow::OnGameListLoadFile(QString game_path) { |
| 365 | BootGame(game_path.toLatin1().data()); | 365 | BootGame(game_path.toLocal8Bit().data()); |
| 366 | } | 366 | } |
| 367 | 367 | ||
| 368 | void GMainWindow::OnMenuLoadFile() { | 368 | void GMainWindow::OnMenuLoadFile() { |
| @@ -374,7 +374,7 @@ void GMainWindow::OnMenuLoadFile() { | |||
| 374 | settings.setValue("romsPath", QFileInfo(filename).path()); | 374 | settings.setValue("romsPath", QFileInfo(filename).path()); |
| 375 | StoreRecentFile(filename); | 375 | StoreRecentFile(filename); |
| 376 | 376 | ||
| 377 | BootGame(filename.toLatin1().data()); | 377 | BootGame(filename.toLocal8Bit().data()); |
| 378 | } | 378 | } |
| 379 | } | 379 | } |
| 380 | 380 | ||
| @@ -386,7 +386,7 @@ void GMainWindow::OnMenuLoadSymbolMap() { | |||
| 386 | if (!filename.isEmpty()) { | 386 | if (!filename.isEmpty()) { |
| 387 | settings.setValue("symbolsPath", QFileInfo(filename).path()); | 387 | settings.setValue("symbolsPath", QFileInfo(filename).path()); |
| 388 | 388 | ||
| 389 | LoadSymbolMap(filename.toLatin1().data()); | 389 | LoadSymbolMap(filename.toLocal8Bit().data()); |
| 390 | } | 390 | } |
| 391 | } | 391 | } |
| 392 | 392 | ||
| @@ -407,7 +407,7 @@ void GMainWindow::OnMenuRecentFile() { | |||
| 407 | QString filename = action->data().toString(); | 407 | QString filename = action->data().toString(); |
| 408 | QFileInfo file_info(filename); | 408 | QFileInfo file_info(filename); |
| 409 | if (file_info.exists()) { | 409 | if (file_info.exists()) { |
| 410 | BootGame(filename.toLatin1().data()); | 410 | BootGame(filename.toLocal8Bit().data()); |
| 411 | StoreRecentFile(filename); // Put the filename on top of the list | 411 | StoreRecentFile(filename); // Put the filename on top of the list |
| 412 | } else { | 412 | } else { |
| 413 | // Display an error message and remove the file from the list. | 413 | // Display an error message and remove the file from the list. |
| @@ -450,6 +450,10 @@ void GMainWindow::OnOpenHotkeysDialog() { | |||
| 450 | 450 | ||
| 451 | void GMainWindow::SetHardwareRendererEnabled(bool enabled) { | 451 | void GMainWindow::SetHardwareRendererEnabled(bool enabled) { |
| 452 | VideoCore::g_hw_renderer_enabled = enabled; | 452 | VideoCore::g_hw_renderer_enabled = enabled; |
| 453 | |||
| 454 | Config config; | ||
| 455 | Settings::values.use_hw_renderer = enabled; | ||
| 456 | config.Save(); | ||
| 453 | } | 457 | } |
| 454 | 458 | ||
| 455 | void GMainWindow::SetGdbstubEnabled(bool enabled) { | 459 | void GMainWindow::SetGdbstubEnabled(bool enabled) { |
| @@ -458,6 +462,10 @@ void GMainWindow::SetGdbstubEnabled(bool enabled) { | |||
| 458 | 462 | ||
| 459 | void GMainWindow::SetShaderJITEnabled(bool enabled) { | 463 | void GMainWindow::SetShaderJITEnabled(bool enabled) { |
| 460 | VideoCore::g_shader_jit_enabled = enabled; | 464 | VideoCore::g_shader_jit_enabled = enabled; |
| 465 | |||
| 466 | Config config; | ||
| 467 | Settings::values.use_shader_jit = enabled; | ||
| 468 | config.Save(); | ||
| 461 | } | 469 | } |
| 462 | 470 | ||
| 463 | void GMainWindow::ToggleWindowMode() { | 471 | void GMainWindow::ToggleWindowMode() { |
| @@ -469,6 +477,7 @@ void GMainWindow::ToggleWindowMode() { | |||
| 469 | if (emulation_running) { | 477 | if (emulation_running) { |
| 470 | render_window->setVisible(true); | 478 | render_window->setVisible(true); |
| 471 | render_window->setFocus(); | 479 | render_window->setFocus(); |
| 480 | game_list->hide(); | ||
| 472 | } | 481 | } |
| 473 | 482 | ||
| 474 | } else { | 483 | } else { |
diff --git a/src/core/arm/skyeye_common/vfp/vfp.cpp b/src/core/arm/skyeye_common/vfp/vfp.cpp index 0537135e2..a27a7e194 100644 --- a/src/core/arm/skyeye_common/vfp/vfp.cpp +++ b/src/core/arm/skyeye_common/vfp/vfp.cpp | |||
| @@ -113,26 +113,26 @@ void VMOVR(ARMul_State* state, u32 single, u32 d, u32 m) | |||
| 113 | /* Miscellaneous functions */ | 113 | /* Miscellaneous functions */ |
| 114 | s32 vfp_get_float(ARMul_State* state, unsigned int reg) | 114 | s32 vfp_get_float(ARMul_State* state, unsigned int reg) |
| 115 | { | 115 | { |
| 116 | LOG_TRACE(Core_ARM11, "VFP get float: s%d=[%08x]\n", reg, state->ExtReg[reg]); | 116 | LOG_TRACE(Core_ARM11, "VFP get float: s%d=[%08x]", reg, state->ExtReg[reg]); |
| 117 | return state->ExtReg[reg]; | 117 | return state->ExtReg[reg]; |
| 118 | } | 118 | } |
| 119 | 119 | ||
| 120 | void vfp_put_float(ARMul_State* state, s32 val, unsigned int reg) | 120 | void vfp_put_float(ARMul_State* state, s32 val, unsigned int reg) |
| 121 | { | 121 | { |
| 122 | LOG_TRACE(Core_ARM11, "VFP put float: s%d <= [%08x]\n", reg, val); | 122 | LOG_TRACE(Core_ARM11, "VFP put float: s%d <= [%08x]", reg, val); |
| 123 | state->ExtReg[reg] = val; | 123 | state->ExtReg[reg] = val; |
| 124 | } | 124 | } |
| 125 | 125 | ||
| 126 | u64 vfp_get_double(ARMul_State* state, unsigned int reg) | 126 | u64 vfp_get_double(ARMul_State* state, unsigned int reg) |
| 127 | { | 127 | { |
| 128 | u64 result = ((u64) state->ExtReg[reg*2+1])<<32 | state->ExtReg[reg*2]; | 128 | u64 result = ((u64) state->ExtReg[reg*2+1])<<32 | state->ExtReg[reg*2]; |
| 129 | LOG_TRACE(Core_ARM11, "VFP get double: s[%d-%d]=[%016llx]\n", reg * 2 + 1, reg * 2, result); | 129 | LOG_TRACE(Core_ARM11, "VFP get double: s[%d-%d]=[%016llx]", reg * 2 + 1, reg * 2, result); |
| 130 | return result; | 130 | return result; |
| 131 | } | 131 | } |
| 132 | 132 | ||
| 133 | void vfp_put_double(ARMul_State* state, u64 val, unsigned int reg) | 133 | void vfp_put_double(ARMul_State* state, u64 val, unsigned int reg) |
| 134 | { | 134 | { |
| 135 | LOG_TRACE(Core_ARM11, "VFP put double: s[%d-%d] <= [%08x-%08x]\n", reg * 2 + 1, reg * 2, (u32)(val >> 32), (u32)(val & 0xffffffff)); | 135 | LOG_TRACE(Core_ARM11, "VFP put double: s[%d-%d] <= [%08x-%08x]", reg * 2 + 1, reg * 2, (u32)(val >> 32), (u32)(val & 0xffffffff)); |
| 136 | state->ExtReg[reg*2] = (u32) (val & 0xffffffff); | 136 | state->ExtReg[reg*2] = (u32) (val & 0xffffffff); |
| 137 | state->ExtReg[reg*2+1] = (u32) (val>>32); | 137 | state->ExtReg[reg*2+1] = (u32) (val>>32); |
| 138 | } | 138 | } |
| @@ -142,10 +142,10 @@ void vfp_put_double(ARMul_State* state, u64 val, unsigned int reg) | |||
| 142 | */ | 142 | */ |
| 143 | void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpscr) | 143 | void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpscr) |
| 144 | { | 144 | { |
| 145 | LOG_TRACE(Core_ARM11, "VFP: raising exceptions %08x\n", exceptions); | 145 | LOG_TRACE(Core_ARM11, "VFP: raising exceptions %08x", exceptions); |
| 146 | 146 | ||
| 147 | if (exceptions == VFP_EXCEPTION_ERROR) { | 147 | if (exceptions == VFP_EXCEPTION_ERROR) { |
| 148 | LOG_CRITICAL(Core_ARM11, "unhandled bounce %x\n", inst); | 148 | LOG_CRITICAL(Core_ARM11, "unhandled bounce %x", inst); |
| 149 | Crash(); | 149 | Crash(); |
| 150 | } | 150 | } |
| 151 | 151 | ||
diff --git a/src/core/arm/skyeye_common/vfp/vfp.h b/src/core/arm/skyeye_common/vfp/vfp.h index 88908da9f..60a63e6de 100644 --- a/src/core/arm/skyeye_common/vfp/vfp.h +++ b/src/core/arm/skyeye_common/vfp/vfp.h | |||
| @@ -22,7 +22,7 @@ | |||
| 22 | 22 | ||
| 23 | #include "core/arm/skyeye_common/vfp/vfp_helper.h" /* for references to cdp SoftFloat functions */ | 23 | #include "core/arm/skyeye_common/vfp/vfp_helper.h" /* for references to cdp SoftFloat functions */ |
| 24 | 24 | ||
| 25 | #define VFP_DEBUG_UNTESTED(x) LOG_TRACE(Core_ARM11, "in func %s, " #x " untested\n", __FUNCTION__); | 25 | #define VFP_DEBUG_UNTESTED(x) LOG_TRACE(Core_ARM11, "in func %s, " #x " untested", __FUNCTION__); |
| 26 | #define CHECK_VFP_ENABLED | 26 | #define CHECK_VFP_ENABLED |
| 27 | #define CHECK_VFP_CDP_RET vfp_raise_exceptions(cpu, ret, inst_cream->instr, cpu->VFP[VFP_FPSCR]); | 27 | #define CHECK_VFP_CDP_RET vfp_raise_exceptions(cpu, ret, inst_cream->instr, cpu->VFP[VFP_FPSCR]); |
| 28 | 28 | ||
diff --git a/src/core/arm/skyeye_common/vfp/vfpdouble.cpp b/src/core/arm/skyeye_common/vfp/vfpdouble.cpp index 857e6ce45..45914d479 100644 --- a/src/core/arm/skyeye_common/vfp/vfpdouble.cpp +++ b/src/core/arm/skyeye_common/vfp/vfpdouble.cpp | |||
| @@ -65,7 +65,7 @@ static struct vfp_double vfp_double_default_qnan = { | |||
| 65 | 65 | ||
| 66 | static void vfp_double_dump(const char *str, struct vfp_double *d) | 66 | static void vfp_double_dump(const char *str, struct vfp_double *d) |
| 67 | { | 67 | { |
| 68 | LOG_TRACE(Core_ARM11, "VFP: %s: sign=%d exponent=%d significand=%016llx\n", | 68 | LOG_TRACE(Core_ARM11, "VFP: %s: sign=%d exponent=%d significand=%016llx", |
| 69 | str, d->sign != 0, d->exponent, d->significand); | 69 | str, d->sign != 0, d->exponent, d->significand); |
| 70 | } | 70 | } |
| 71 | 71 | ||
| @@ -155,7 +155,7 @@ u32 vfp_double_normaliseround(ARMul_State* state, int dd, struct vfp_double *vd, | |||
| 155 | } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vd->sign != 0)) | 155 | } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vd->sign != 0)) |
| 156 | incr = (1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1; | 156 | incr = (1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1; |
| 157 | 157 | ||
| 158 | LOG_TRACE(Core_ARM11, "VFP: rounding increment = 0x%08llx\n", incr); | 158 | LOG_TRACE(Core_ARM11, "VFP: rounding increment = 0x%08llx", incr); |
| 159 | 159 | ||
| 160 | /* | 160 | /* |
| 161 | * Is our rounding going to overflow? | 161 | * Is our rounding going to overflow? |
| @@ -210,7 +210,7 @@ pack: | |||
| 210 | vfp_double_dump("pack: final", vd); | 210 | vfp_double_dump("pack: final", vd); |
| 211 | { | 211 | { |
| 212 | s64 d = vfp_double_pack(vd); | 212 | s64 d = vfp_double_pack(vd); |
| 213 | LOG_TRACE(Core_ARM11, "VFP: %s: d(d%d)=%016llx exceptions=%08x\n", func, | 213 | LOG_TRACE(Core_ARM11, "VFP: %s: d(d%d)=%016llx exceptions=%08x", func, |
| 214 | dd, d, exceptions); | 214 | dd, d, exceptions); |
| 215 | vfp_put_double(state, d, dd); | 215 | vfp_put_double(state, d, dd); |
| 216 | } | 216 | } |
| @@ -267,28 +267,28 @@ vfp_propagate_nan(struct vfp_double *vdd, struct vfp_double *vdn, | |||
| 267 | */ | 267 | */ |
| 268 | static u32 vfp_double_fabs(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) | 268 | static u32 vfp_double_fabs(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) |
| 269 | { | 269 | { |
| 270 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 270 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 271 | vfp_put_double(state, vfp_double_packed_abs(vfp_get_double(state, dm)), dd); | 271 | vfp_put_double(state, vfp_double_packed_abs(vfp_get_double(state, dm)), dd); |
| 272 | return 0; | 272 | return 0; |
| 273 | } | 273 | } |
| 274 | 274 | ||
| 275 | static u32 vfp_double_fcpy(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) | 275 | static u32 vfp_double_fcpy(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) |
| 276 | { | 276 | { |
| 277 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 277 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 278 | vfp_put_double(state, vfp_get_double(state, dm), dd); | 278 | vfp_put_double(state, vfp_get_double(state, dm), dd); |
| 279 | return 0; | 279 | return 0; |
| 280 | } | 280 | } |
| 281 | 281 | ||
| 282 | static u32 vfp_double_fneg(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) | 282 | static u32 vfp_double_fneg(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) |
| 283 | { | 283 | { |
| 284 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 284 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 285 | vfp_put_double(state, vfp_double_packed_negate(vfp_get_double(state, dm)), dd); | 285 | vfp_put_double(state, vfp_double_packed_negate(vfp_get_double(state, dm)), dd); |
| 286 | return 0; | 286 | return 0; |
| 287 | } | 287 | } |
| 288 | 288 | ||
| 289 | static u32 vfp_double_fsqrt(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) | 289 | static u32 vfp_double_fsqrt(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) |
| 290 | { | 290 | { |
| 291 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 291 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 292 | vfp_double vdm, vdd, *vdp; | 292 | vfp_double vdm, vdd, *vdp; |
| 293 | int ret, tm; | 293 | int ret, tm; |
| 294 | 294 | ||
| @@ -383,7 +383,7 @@ static u32 vfp_compare(ARMul_State* state, int dd, int signal_on_qnan, int dm, u | |||
| 383 | s64 d, m; | 383 | s64 d, m; |
| 384 | u32 ret = 0; | 384 | u32 ret = 0; |
| 385 | 385 | ||
| 386 | LOG_TRACE(Core_ARM11, "In %s, state=0x%p, fpscr=0x%x\n", __FUNCTION__, state, fpscr); | 386 | LOG_TRACE(Core_ARM11, "In %s, state=0x%p, fpscr=0x%x", __FUNCTION__, state, fpscr); |
| 387 | m = vfp_get_double(state, dm); | 387 | m = vfp_get_double(state, dm); |
| 388 | if (vfp_double_packed_exponent(m) == 2047 && vfp_double_packed_mantissa(m)) { | 388 | if (vfp_double_packed_exponent(m) == 2047 && vfp_double_packed_mantissa(m)) { |
| 389 | ret |= FPSCR_CFLAG | FPSCR_VFLAG; | 389 | ret |= FPSCR_CFLAG | FPSCR_VFLAG; |
| @@ -438,32 +438,32 @@ static u32 vfp_compare(ARMul_State* state, int dd, int signal_on_qnan, int dm, u | |||
| 438 | ret |= FPSCR_CFLAG; | 438 | ret |= FPSCR_CFLAG; |
| 439 | } | 439 | } |
| 440 | } | 440 | } |
| 441 | LOG_TRACE(Core_ARM11, "In %s, state=0x%p, ret=0x%x\n", __FUNCTION__, state, ret); | 441 | LOG_TRACE(Core_ARM11, "In %s, state=0x%p, ret=0x%x", __FUNCTION__, state, ret); |
| 442 | 442 | ||
| 443 | return ret; | 443 | return ret; |
| 444 | } | 444 | } |
| 445 | 445 | ||
| 446 | static u32 vfp_double_fcmp(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) | 446 | static u32 vfp_double_fcmp(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) |
| 447 | { | 447 | { |
| 448 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 448 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 449 | return vfp_compare(state, dd, 0, dm, fpscr); | 449 | return vfp_compare(state, dd, 0, dm, fpscr); |
| 450 | } | 450 | } |
| 451 | 451 | ||
| 452 | static u32 vfp_double_fcmpe(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) | 452 | static u32 vfp_double_fcmpe(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) |
| 453 | { | 453 | { |
| 454 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 454 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 455 | return vfp_compare(state, dd, 1, dm, fpscr); | 455 | return vfp_compare(state, dd, 1, dm, fpscr); |
| 456 | } | 456 | } |
| 457 | 457 | ||
| 458 | static u32 vfp_double_fcmpz(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) | 458 | static u32 vfp_double_fcmpz(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) |
| 459 | { | 459 | { |
| 460 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 460 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 461 | return vfp_compare(state, dd, 0, VFP_REG_ZERO, fpscr); | 461 | return vfp_compare(state, dd, 0, VFP_REG_ZERO, fpscr); |
| 462 | } | 462 | } |
| 463 | 463 | ||
| 464 | static u32 vfp_double_fcmpez(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) | 464 | static u32 vfp_double_fcmpez(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) |
| 465 | { | 465 | { |
| 466 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 466 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 467 | return vfp_compare(state, dd, 1, VFP_REG_ZERO, fpscr); | 467 | return vfp_compare(state, dd, 1, VFP_REG_ZERO, fpscr); |
| 468 | } | 468 | } |
| 469 | 469 | ||
| @@ -474,7 +474,7 @@ static u32 vfp_double_fcvts(ARMul_State* state, int sd, int unused, int dm, u32 | |||
| 474 | int tm; | 474 | int tm; |
| 475 | u32 exceptions = 0; | 475 | u32 exceptions = 0; |
| 476 | 476 | ||
| 477 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 477 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 478 | vfp_double_unpack(&vdm, vfp_get_double(state, dm), &fpscr); | 478 | vfp_double_unpack(&vdm, vfp_get_double(state, dm), &fpscr); |
| 479 | 479 | ||
| 480 | tm = vfp_double_type(&vdm); | 480 | tm = vfp_double_type(&vdm); |
| @@ -516,7 +516,7 @@ static u32 vfp_double_fuito(ARMul_State* state, int dd, int unused, int dm, u32 | |||
| 516 | struct vfp_double vdm; | 516 | struct vfp_double vdm; |
| 517 | u32 m = vfp_get_float(state, dm); | 517 | u32 m = vfp_get_float(state, dm); |
| 518 | 518 | ||
| 519 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 519 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 520 | vdm.sign = 0; | 520 | vdm.sign = 0; |
| 521 | vdm.exponent = 1023 + 63 - 1; | 521 | vdm.exponent = 1023 + 63 - 1; |
| 522 | vdm.significand = (u64)m; | 522 | vdm.significand = (u64)m; |
| @@ -529,7 +529,7 @@ static u32 vfp_double_fsito(ARMul_State* state, int dd, int unused, int dm, u32 | |||
| 529 | struct vfp_double vdm; | 529 | struct vfp_double vdm; |
| 530 | u32 m = vfp_get_float(state, dm); | 530 | u32 m = vfp_get_float(state, dm); |
| 531 | 531 | ||
| 532 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 532 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 533 | vdm.sign = (m & 0x80000000) >> 16; | 533 | vdm.sign = (m & 0x80000000) >> 16; |
| 534 | vdm.exponent = 1023 + 63 - 1; | 534 | vdm.exponent = 1023 + 63 - 1; |
| 535 | vdm.significand = vdm.sign ? (~m + 1) : m; | 535 | vdm.significand = vdm.sign ? (~m + 1) : m; |
| @@ -544,7 +544,7 @@ static u32 vfp_double_ftoui(ARMul_State* state, int sd, int unused, int dm, u32 | |||
| 544 | int rmode = fpscr & FPSCR_RMODE_MASK; | 544 | int rmode = fpscr & FPSCR_RMODE_MASK; |
| 545 | int tm; | 545 | int tm; |
| 546 | 546 | ||
| 547 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 547 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 548 | vfp_double_unpack(&vdm, vfp_get_double(state, dm), &fpscr); | 548 | vfp_double_unpack(&vdm, vfp_get_double(state, dm), &fpscr); |
| 549 | 549 | ||
| 550 | /* | 550 | /* |
| @@ -605,7 +605,7 @@ static u32 vfp_double_ftoui(ARMul_State* state, int sd, int unused, int dm, u32 | |||
| 605 | } | 605 | } |
| 606 | } | 606 | } |
| 607 | 607 | ||
| 608 | LOG_TRACE(Core_ARM11, "VFP: ftoui: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions); | 608 | LOG_TRACE(Core_ARM11, "VFP: ftoui: d(s%d)=%08x exceptions=%08x", sd, d, exceptions); |
| 609 | 609 | ||
| 610 | vfp_put_float(state, d, sd); | 610 | vfp_put_float(state, d, sd); |
| 611 | 611 | ||
| @@ -614,7 +614,7 @@ static u32 vfp_double_ftoui(ARMul_State* state, int sd, int unused, int dm, u32 | |||
| 614 | 614 | ||
| 615 | static u32 vfp_double_ftouiz(ARMul_State* state, int sd, int unused, int dm, u32 fpscr) | 615 | static u32 vfp_double_ftouiz(ARMul_State* state, int sd, int unused, int dm, u32 fpscr) |
| 616 | { | 616 | { |
| 617 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 617 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 618 | return vfp_double_ftoui(state, sd, unused, dm, FPSCR_ROUND_TOZERO); | 618 | return vfp_double_ftoui(state, sd, unused, dm, FPSCR_ROUND_TOZERO); |
| 619 | } | 619 | } |
| 620 | 620 | ||
| @@ -625,7 +625,7 @@ static u32 vfp_double_ftosi(ARMul_State* state, int sd, int unused, int dm, u32 | |||
| 625 | int rmode = fpscr & FPSCR_RMODE_MASK; | 625 | int rmode = fpscr & FPSCR_RMODE_MASK; |
| 626 | int tm; | 626 | int tm; |
| 627 | 627 | ||
| 628 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 628 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 629 | vfp_double_unpack(&vdm, vfp_get_double(state, dm), &fpscr); | 629 | vfp_double_unpack(&vdm, vfp_get_double(state, dm), &fpscr); |
| 630 | vfp_double_dump("VDM", &vdm); | 630 | vfp_double_dump("VDM", &vdm); |
| 631 | 631 | ||
| @@ -682,7 +682,7 @@ static u32 vfp_double_ftosi(ARMul_State* state, int sd, int unused, int dm, u32 | |||
| 682 | } | 682 | } |
| 683 | } | 683 | } |
| 684 | 684 | ||
| 685 | LOG_TRACE(Core_ARM11, "VFP: ftosi: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions); | 685 | LOG_TRACE(Core_ARM11, "VFP: ftosi: d(s%d)=%08x exceptions=%08x", sd, d, exceptions); |
| 686 | 686 | ||
| 687 | vfp_put_float(state, (s32)d, sd); | 687 | vfp_put_float(state, (s32)d, sd); |
| 688 | 688 | ||
| @@ -691,7 +691,7 @@ static u32 vfp_double_ftosi(ARMul_State* state, int sd, int unused, int dm, u32 | |||
| 691 | 691 | ||
| 692 | static u32 vfp_double_ftosiz(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) | 692 | static u32 vfp_double_ftosiz(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) |
| 693 | { | 693 | { |
| 694 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 694 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 695 | return vfp_double_ftosi(state, dd, unused, dm, FPSCR_ROUND_TOZERO); | 695 | return vfp_double_ftosi(state, dd, unused, dm, FPSCR_ROUND_TOZERO); |
| 696 | } | 696 | } |
| 697 | 697 | ||
| @@ -775,7 +775,7 @@ u32 vfp_double_add(struct vfp_double *vdd, struct vfp_double *vdn,struct vfp_dou | |||
| 775 | 775 | ||
| 776 | if (vdn->significand & (1ULL << 63) || | 776 | if (vdn->significand & (1ULL << 63) || |
| 777 | vdm->significand & (1ULL << 63)) { | 777 | vdm->significand & (1ULL << 63)) { |
| 778 | LOG_INFO(Core_ARM11, "VFP: bad FP values in %s\n", __func__); | 778 | LOG_INFO(Core_ARM11, "VFP: bad FP values in %s", __func__); |
| 779 | vfp_double_dump("VDN", vdn); | 779 | vfp_double_dump("VDN", vdn); |
| 780 | vfp_double_dump("VDM", vdm); | 780 | vfp_double_dump("VDM", vdm); |
| 781 | } | 781 | } |
| @@ -843,7 +843,7 @@ vfp_double_multiply(struct vfp_double *vdd, struct vfp_double *vdn, | |||
| 843 | */ | 843 | */ |
| 844 | if (vdn->exponent < vdm->exponent) { | 844 | if (vdn->exponent < vdm->exponent) { |
| 845 | std::swap(vdm, vdn); | 845 | std::swap(vdm, vdn); |
| 846 | LOG_TRACE(Core_ARM11, "VFP: swapping M <-> N\n"); | 846 | LOG_TRACE(Core_ARM11, "VFP: swapping M <-> N"); |
| 847 | } | 847 | } |
| 848 | 848 | ||
| 849 | vdd->sign = vdn->sign ^ vdm->sign; | 849 | vdd->sign = vdn->sign ^ vdm->sign; |
| @@ -927,7 +927,7 @@ vfp_double_multiply_accumulate(ARMul_State* state, int dd, int dn, int dm, u32 f | |||
| 927 | */ | 927 | */ |
| 928 | static u32 vfp_double_fmac(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) | 928 | static u32 vfp_double_fmac(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) |
| 929 | { | 929 | { |
| 930 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 930 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 931 | return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, 0, "fmac"); | 931 | return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, 0, "fmac"); |
| 932 | } | 932 | } |
| 933 | 933 | ||
| @@ -936,7 +936,7 @@ static u32 vfp_double_fmac(ARMul_State* state, int dd, int dn, int dm, u32 fpscr | |||
| 936 | */ | 936 | */ |
| 937 | static u32 vfp_double_fnmac(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) | 937 | static u32 vfp_double_fnmac(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) |
| 938 | { | 938 | { |
| 939 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 939 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 940 | return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_MULTIPLY, "fnmac"); | 940 | return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_MULTIPLY, "fnmac"); |
| 941 | } | 941 | } |
| 942 | 942 | ||
| @@ -945,7 +945,7 @@ static u32 vfp_double_fnmac(ARMul_State* state, int dd, int dn, int dm, u32 fpsc | |||
| 945 | */ | 945 | */ |
| 946 | static u32 vfp_double_fmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) | 946 | static u32 vfp_double_fmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) |
| 947 | { | 947 | { |
| 948 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 948 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 949 | return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_SUBTRACT, "fmsc"); | 949 | return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_SUBTRACT, "fmsc"); |
| 950 | } | 950 | } |
| 951 | 951 | ||
| @@ -954,7 +954,7 @@ static u32 vfp_double_fmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpscr | |||
| 954 | */ | 954 | */ |
| 955 | static u32 vfp_double_fnmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) | 955 | static u32 vfp_double_fnmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) |
| 956 | { | 956 | { |
| 957 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 957 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 958 | return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_SUBTRACT | NEG_MULTIPLY, "fnmsc"); | 958 | return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_SUBTRACT | NEG_MULTIPLY, "fnmsc"); |
| 959 | } | 959 | } |
| 960 | 960 | ||
| @@ -966,7 +966,7 @@ static u32 vfp_double_fmul(ARMul_State* state, int dd, int dn, int dm, u32 fpscr | |||
| 966 | struct vfp_double vdd, vdn, vdm; | 966 | struct vfp_double vdd, vdn, vdm; |
| 967 | u32 exceptions; | 967 | u32 exceptions; |
| 968 | 968 | ||
| 969 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 969 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 970 | vfp_double_unpack(&vdn, vfp_get_double(state, dn), &fpscr); | 970 | vfp_double_unpack(&vdn, vfp_get_double(state, dn), &fpscr); |
| 971 | if (vdn.exponent == 0 && vdn.significand) | 971 | if (vdn.exponent == 0 && vdn.significand) |
| 972 | vfp_double_normalise_denormal(&vdn); | 972 | vfp_double_normalise_denormal(&vdn); |
| @@ -987,7 +987,7 @@ static u32 vfp_double_fnmul(ARMul_State* state, int dd, int dn, int dm, u32 fpsc | |||
| 987 | struct vfp_double vdd, vdn, vdm; | 987 | struct vfp_double vdd, vdn, vdm; |
| 988 | u32 exceptions; | 988 | u32 exceptions; |
| 989 | 989 | ||
| 990 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 990 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 991 | vfp_double_unpack(&vdn, vfp_get_double(state, dn), &fpscr); | 991 | vfp_double_unpack(&vdn, vfp_get_double(state, dn), &fpscr); |
| 992 | if (vdn.exponent == 0 && vdn.significand) | 992 | if (vdn.exponent == 0 && vdn.significand) |
| 993 | vfp_double_normalise_denormal(&vdn); | 993 | vfp_double_normalise_denormal(&vdn); |
| @@ -1010,7 +1010,7 @@ static u32 vfp_double_fadd(ARMul_State* state, int dd, int dn, int dm, u32 fpscr | |||
| 1010 | struct vfp_double vdd, vdn, vdm; | 1010 | struct vfp_double vdd, vdn, vdm; |
| 1011 | u32 exceptions; | 1011 | u32 exceptions; |
| 1012 | 1012 | ||
| 1013 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 1013 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 1014 | vfp_double_unpack(&vdn, vfp_get_double(state, dn), &fpscr); | 1014 | vfp_double_unpack(&vdn, vfp_get_double(state, dn), &fpscr); |
| 1015 | if (vdn.exponent == 0 && vdn.significand) | 1015 | if (vdn.exponent == 0 && vdn.significand) |
| 1016 | vfp_double_normalise_denormal(&vdn); | 1016 | vfp_double_normalise_denormal(&vdn); |
| @@ -1032,7 +1032,7 @@ static u32 vfp_double_fsub(ARMul_State* state, int dd, int dn, int dm, u32 fpscr | |||
| 1032 | struct vfp_double vdd, vdn, vdm; | 1032 | struct vfp_double vdd, vdn, vdm; |
| 1033 | u32 exceptions; | 1033 | u32 exceptions; |
| 1034 | 1034 | ||
| 1035 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 1035 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 1036 | vfp_double_unpack(&vdn, vfp_get_double(state, dn), &fpscr); | 1036 | vfp_double_unpack(&vdn, vfp_get_double(state, dn), &fpscr); |
| 1037 | if (vdn.exponent == 0 && vdn.significand) | 1037 | if (vdn.exponent == 0 && vdn.significand) |
| 1038 | vfp_double_normalise_denormal(&vdn); | 1038 | vfp_double_normalise_denormal(&vdn); |
| @@ -1060,7 +1060,7 @@ static u32 vfp_double_fdiv(ARMul_State* state, int dd, int dn, int dm, u32 fpscr | |||
| 1060 | u32 exceptions = 0; | 1060 | u32 exceptions = 0; |
| 1061 | int tm, tn; | 1061 | int tm, tn; |
| 1062 | 1062 | ||
| 1063 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 1063 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 1064 | vfp_double_unpack(&vdn, vfp_get_double(state, dn), &fpscr); | 1064 | vfp_double_unpack(&vdn, vfp_get_double(state, dn), &fpscr); |
| 1065 | vfp_double_unpack(&vdm, vfp_get_double(state, dm), &fpscr); | 1065 | vfp_double_unpack(&vdm, vfp_get_double(state, dm), &fpscr); |
| 1066 | 1066 | ||
| @@ -1185,7 +1185,7 @@ u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr) | |||
| 1185 | unsigned int vecitr, veclen, vecstride; | 1185 | unsigned int vecitr, veclen, vecstride; |
| 1186 | struct op *fop; | 1186 | struct op *fop; |
| 1187 | 1187 | ||
| 1188 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 1188 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 1189 | vecstride = (1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK)); | 1189 | vecstride = (1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK)); |
| 1190 | 1190 | ||
| 1191 | fop = (op == FOP_EXT) ? &fops_ext[FEXT_TO_IDX(inst)] : &fops[FOP_TO_IDX(op)]; | 1191 | fop = (op == FOP_EXT) ? &fops_ext[FEXT_TO_IDX(inst)] : &fops[FOP_TO_IDX(op)]; |
| @@ -1216,7 +1216,7 @@ u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr) | |||
| 1216 | else | 1216 | else |
| 1217 | veclen = fpscr & FPSCR_LENGTH_MASK; | 1217 | veclen = fpscr & FPSCR_LENGTH_MASK; |
| 1218 | 1218 | ||
| 1219 | LOG_TRACE(Core_ARM11, "VFP: vecstride=%u veclen=%u\n", vecstride, | 1219 | LOG_TRACE(Core_ARM11, "VFP: vecstride=%u veclen=%u", vecstride, |
| 1220 | (veclen >> FPSCR_LENGTH_BIT) + 1); | 1220 | (veclen >> FPSCR_LENGTH_BIT) + 1); |
| 1221 | 1221 | ||
| 1222 | if (!fop->fn) { | 1222 | if (!fop->fn) { |
| @@ -1230,16 +1230,16 @@ u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr) | |||
| 1230 | 1230 | ||
| 1231 | type = (fop->flags & OP_SD) ? 's' : 'd'; | 1231 | type = (fop->flags & OP_SD) ? 's' : 'd'; |
| 1232 | if (op == FOP_EXT) | 1232 | if (op == FOP_EXT) |
| 1233 | LOG_TRACE(Core_ARM11, "VFP: itr%d (%c%u) = op[%u] (d%u)\n", | 1233 | LOG_TRACE(Core_ARM11, "VFP: itr%d (%c%u) = op[%u] (d%u)", |
| 1234 | vecitr >> FPSCR_LENGTH_BIT, | 1234 | vecitr >> FPSCR_LENGTH_BIT, |
| 1235 | type, dest, dn, dm); | 1235 | type, dest, dn, dm); |
| 1236 | else | 1236 | else |
| 1237 | LOG_TRACE(Core_ARM11, "VFP: itr%d (%c%u) = (d%u) op[%u] (d%u)\n", | 1237 | LOG_TRACE(Core_ARM11, "VFP: itr%d (%c%u) = (d%u) op[%u] (d%u)", |
| 1238 | vecitr >> FPSCR_LENGTH_BIT, | 1238 | vecitr >> FPSCR_LENGTH_BIT, |
| 1239 | type, dest, dn, FOP_TO_IDX(op), dm); | 1239 | type, dest, dn, FOP_TO_IDX(op), dm); |
| 1240 | 1240 | ||
| 1241 | except = fop->fn(state, dest, dn, dm, fpscr); | 1241 | except = fop->fn(state, dest, dn, dm, fpscr); |
| 1242 | LOG_TRACE(Core_ARM11, "VFP: itr%d: exceptions=%08x\n", | 1242 | LOG_TRACE(Core_ARM11, "VFP: itr%d: exceptions=%08x", |
| 1243 | vecitr >> FPSCR_LENGTH_BIT, except); | 1243 | vecitr >> FPSCR_LENGTH_BIT, except); |
| 1244 | 1244 | ||
| 1245 | exceptions |= except; | 1245 | exceptions |= except; |
diff --git a/src/core/file_sys/archive_backend.h b/src/core/file_sys/archive_backend.h index c6a1be79d..e7a59a1ed 100644 --- a/src/core/file_sys/archive_backend.h +++ b/src/core/file_sys/archive_backend.h | |||
| @@ -131,6 +131,12 @@ public: | |||
| 131 | * @return Opened directory, or nullptr | 131 | * @return Opened directory, or nullptr |
| 132 | */ | 132 | */ |
| 133 | virtual std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const = 0; | 133 | virtual std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const = 0; |
| 134 | |||
| 135 | /** | ||
| 136 | * Get the free space | ||
| 137 | * @return The number of free bytes in the archive | ||
| 138 | */ | ||
| 139 | virtual u64 GetFreeBytes() const = 0; | ||
| 134 | }; | 140 | }; |
| 135 | 141 | ||
| 136 | class ArchiveFactory : NonCopyable { | 142 | class ArchiveFactory : NonCopyable { |
diff --git a/src/core/file_sys/disk_archive.cpp b/src/core/file_sys/disk_archive.cpp index e9ecd2b1c..0ba502200 100644 --- a/src/core/file_sys/disk_archive.cpp +++ b/src/core/file_sys/disk_archive.cpp | |||
| @@ -74,6 +74,11 @@ std::unique_ptr<DirectoryBackend> DiskArchive::OpenDirectory(const Path& path) c | |||
| 74 | return std::move(directory); | 74 | return std::move(directory); |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | u64 DiskArchive::GetFreeBytes() const { | ||
| 78 | // TODO: Stubbed to return 1GiB | ||
| 79 | return 1024 * 1024 * 1024; | ||
| 80 | } | ||
| 81 | |||
| 77 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 82 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 78 | 83 | ||
| 79 | DiskFile::DiskFile(const DiskArchive& archive, const Path& path, const Mode mode) { | 84 | DiskFile::DiskFile(const DiskArchive& archive, const Path& path, const Mode mode) { |
diff --git a/src/core/file_sys/disk_archive.h b/src/core/file_sys/disk_archive.h index aaac65b17..ef9a98057 100644 --- a/src/core/file_sys/disk_archive.h +++ b/src/core/file_sys/disk_archive.h | |||
| @@ -41,6 +41,7 @@ public: | |||
| 41 | bool CreateDirectory(const Path& path) const override; | 41 | bool CreateDirectory(const Path& path) const override; |
| 42 | bool RenameDirectory(const Path& src_path, const Path& dest_path) const override; | 42 | bool RenameDirectory(const Path& src_path, const Path& dest_path) const override; |
| 43 | std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override; | 43 | std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override; |
| 44 | u64 GetFreeBytes() const override; | ||
| 44 | 45 | ||
| 45 | protected: | 46 | protected: |
| 46 | friend class DiskFile; | 47 | friend class DiskFile; |
diff --git a/src/core/file_sys/ivfc_archive.cpp b/src/core/file_sys/ivfc_archive.cpp index 441ca9b53..2efc31a8c 100644 --- a/src/core/file_sys/ivfc_archive.cpp +++ b/src/core/file_sys/ivfc_archive.cpp | |||
| @@ -59,6 +59,11 @@ std::unique_ptr<DirectoryBackend> IVFCArchive::OpenDirectory(const Path& path) c | |||
| 59 | return Common::make_unique<IVFCDirectory>(); | 59 | return Common::make_unique<IVFCDirectory>(); |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | u64 IVFCArchive::GetFreeBytes() const { | ||
| 63 | LOG_WARNING(Service_FS, "Attempted to get the free space in an IVFC archive"); | ||
| 64 | return 0; | ||
| 65 | } | ||
| 66 | |||
| 62 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 67 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 63 | 68 | ||
| 64 | size_t IVFCFile::Read(const u64 offset, const size_t length, u8* buffer) const { | 69 | size_t IVFCFile::Read(const u64 offset, const size_t length, u8* buffer) const { |
diff --git a/src/core/file_sys/ivfc_archive.h b/src/core/file_sys/ivfc_archive.h index c15a6c4ae..f3fd82de4 100644 --- a/src/core/file_sys/ivfc_archive.h +++ b/src/core/file_sys/ivfc_archive.h | |||
| @@ -42,6 +42,7 @@ public: | |||
| 42 | bool CreateDirectory(const Path& path) const override; | 42 | bool CreateDirectory(const Path& path) const override; |
| 43 | bool RenameDirectory(const Path& src_path, const Path& dest_path) const override; | 43 | bool RenameDirectory(const Path& src_path, const Path& dest_path) const override; |
| 44 | std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override; | 44 | std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override; |
| 45 | u64 GetFreeBytes() const override; | ||
| 45 | 46 | ||
| 46 | protected: | 47 | protected: |
| 47 | std::shared_ptr<FileUtil::IOFile> romfs_file; | 48 | std::shared_ptr<FileUtil::IOFile> romfs_file; |
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index c10126513..00fa995f6 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -220,7 +220,7 @@ static void SwitchContext(Thread* new_thread) { | |||
| 220 | 220 | ||
| 221 | // Clean up the thread's wait_objects, they'll be restored if needed during | 221 | // Clean up the thread's wait_objects, they'll be restored if needed during |
| 222 | // the svcWaitSynchronization call | 222 | // the svcWaitSynchronization call |
| 223 | for (int i = 0; i < new_thread->wait_objects.size(); ++i) { | 223 | for (size_t i = 0; i < new_thread->wait_objects.size(); ++i) { |
| 224 | SharedPtr<WaitObject> object = new_thread->wait_objects[i]; | 224 | SharedPtr<WaitObject> object = new_thread->wait_objects[i]; |
| 225 | object->RemoveWaitingThread(new_thread); | 225 | object->RemoveWaitingThread(new_thread); |
| 226 | } | 226 | } |
diff --git a/src/core/hle/service/csnd_snd.cpp b/src/core/hle/service/csnd_snd.cpp index 6a1d961ac..ce2877f57 100644 --- a/src/core/hle/service/csnd_snd.cpp +++ b/src/core/hle/service/csnd_snd.cpp | |||
| @@ -3,6 +3,8 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "core/hle/hle.h" | 5 | #include "core/hle/hle.h" |
| 6 | #include "core/hle/kernel/mutex.h" | ||
| 7 | #include "core/hle/kernel/shared_memory.h" | ||
| 6 | #include "core/hle/service/csnd_snd.h" | 8 | #include "core/hle/service/csnd_snd.h" |
| 7 | 9 | ||
| 8 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 10 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| @@ -11,11 +13,11 @@ | |||
| 11 | namespace CSND_SND { | 13 | namespace CSND_SND { |
| 12 | 14 | ||
| 13 | const Interface::FunctionInfo FunctionTable[] = { | 15 | const Interface::FunctionInfo FunctionTable[] = { |
| 14 | {0x00010140, nullptr, "Initialize"}, | 16 | {0x00010140, Initialize, "Initialize"}, |
| 15 | {0x00020000, nullptr, "Shutdown"}, | 17 | {0x00020000, Shutdown, "Shutdown"}, |
| 16 | {0x00030040, nullptr, "ExecuteType0Commands"}, | 18 | {0x00030040, ExecuteType0Commands, "ExecuteType0Commands"}, |
| 17 | {0x00040080, nullptr, "ExecuteType1Commands"}, | 19 | {0x00040080, nullptr, "ExecuteType1Commands"}, |
| 18 | {0x00050000, nullptr, "AcquireSoundChannels"}, | 20 | {0x00050000, AcquireSoundChannels, "AcquireSoundChannels"}, |
| 19 | {0x00060000, nullptr, "ReleaseSoundChannels"}, | 21 | {0x00060000, nullptr, "ReleaseSoundChannels"}, |
| 20 | {0x00070000, nullptr, "AcquireCaptureDevice"}, | 22 | {0x00070000, nullptr, "AcquireCaptureDevice"}, |
| 21 | {0x00080040, nullptr, "ReleaseCaptureDevice"}, | 23 | {0x00080040, nullptr, "ReleaseCaptureDevice"}, |
| @@ -31,4 +33,51 @@ Interface::Interface() { | |||
| 31 | Register(FunctionTable); | 33 | Register(FunctionTable); |
| 32 | } | 34 | } |
| 33 | 35 | ||
| 36 | static Kernel::SharedPtr<Kernel::SharedMemory> shared_memory = nullptr; | ||
| 37 | static Kernel::SharedPtr<Kernel::Mutex> mutex = nullptr; | ||
| 38 | |||
| 39 | void Initialize(Service::Interface* self) { | ||
| 40 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 41 | |||
| 42 | shared_memory = Kernel::SharedMemory::Create(cmd_buff[1], | ||
| 43 | Kernel::MemoryPermission::ReadWrite, | ||
| 44 | Kernel::MemoryPermission::ReadWrite, "CSNDSharedMem"); | ||
| 45 | |||
| 46 | mutex = Kernel::Mutex::Create(false); | ||
| 47 | |||
| 48 | cmd_buff[1] = 0; | ||
| 49 | cmd_buff[2] = 0x4000000; | ||
| 50 | cmd_buff[3] = Kernel::g_handle_table.Create(mutex).MoveFrom(); | ||
| 51 | cmd_buff[4] = Kernel::g_handle_table.Create(shared_memory).MoveFrom(); | ||
| 52 | } | ||
| 53 | |||
| 54 | void ExecuteType0Commands(Service::Interface* self) { | ||
| 55 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 56 | |||
| 57 | if (shared_memory != nullptr) { | ||
| 58 | struct Type0Command* command = reinterpret_cast<struct Type0Command*>( | ||
| 59 | shared_memory->GetPointer(cmd_buff[1])); | ||
| 60 | if (command == nullptr) { | ||
| 61 | cmd_buff[1] = 1; | ||
| 62 | }else{ | ||
| 63 | LOG_WARNING(Service, "(STUBBED) CSND_SND::ExecuteType0Commands"); | ||
| 64 | command->finished |= 1; | ||
| 65 | cmd_buff[1] = 0; | ||
| 66 | } | ||
| 67 | }else{ | ||
| 68 | cmd_buff[1] = 1; | ||
| 69 | } | ||
| 70 | } | ||
| 71 | |||
| 72 | void AcquireSoundChannels(Service::Interface* self) { | ||
| 73 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 74 | cmd_buff[1] = 0; | ||
| 75 | cmd_buff[2] = 0xFFFFFF00; | ||
| 76 | } | ||
| 77 | |||
| 78 | void Shutdown(Service::Interface* self) { | ||
| 79 | shared_memory = nullptr; | ||
| 80 | mutex = nullptr; | ||
| 81 | } | ||
| 82 | |||
| 34 | } // namespace | 83 | } // namespace |
diff --git a/src/core/hle/service/csnd_snd.h b/src/core/hle/service/csnd_snd.h index a84752473..e861f3327 100644 --- a/src/core/hle/service/csnd_snd.h +++ b/src/core/hle/service/csnd_snd.h | |||
| @@ -20,4 +20,17 @@ public: | |||
| 20 | } | 20 | } |
| 21 | }; | 21 | }; |
| 22 | 22 | ||
| 23 | struct Type0Command { | ||
| 24 | // command id and next command offset | ||
| 25 | u32 command_id; | ||
| 26 | u32 finished; | ||
| 27 | u32 flags; | ||
| 28 | u8 parameters[20]; | ||
| 29 | }; | ||
| 30 | |||
| 31 | void Initialize(Service::Interface* self); | ||
| 32 | void ExecuteType0Commands(Service::Interface* self); | ||
| 33 | void AcquireSoundChannels(Service::Interface* self); | ||
| 34 | void Shutdown(Service::Interface* self); | ||
| 35 | |||
| 23 | } // namespace | 36 | } // namespace |
diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index 6c0df67c3..d64b3656a 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp | |||
| @@ -403,6 +403,13 @@ ResultVal<Kernel::SharedPtr<Directory>> OpenDirectoryFromArchive(ArchiveHandle a | |||
| 403 | return MakeResult<Kernel::SharedPtr<Directory>>(std::move(directory)); | 403 | return MakeResult<Kernel::SharedPtr<Directory>>(std::move(directory)); |
| 404 | } | 404 | } |
| 405 | 405 | ||
| 406 | ResultVal<u64> GetFreeBytesInArchive(ArchiveHandle archive_handle) { | ||
| 407 | ArchiveBackend* archive = GetArchive(archive_handle); | ||
| 408 | if (archive == nullptr) | ||
| 409 | return ERR_INVALID_HANDLE; | ||
| 410 | return MakeResult<u64>(archive->GetFreeBytes()); | ||
| 411 | } | ||
| 412 | |||
| 406 | ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::Path& path) { | 413 | ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::Path& path) { |
| 407 | auto archive_itr = id_code_map.find(id_code); | 414 | auto archive_itr = id_code_map.find(id_code); |
| 408 | if (archive_itr == id_code_map.end()) { | 415 | if (archive_itr == id_code_map.end()) { |
diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h index 6f7048710..952deb4d4 100644 --- a/src/core/hle/service/fs/archive.h +++ b/src/core/hle/service/fs/archive.h | |||
| @@ -167,6 +167,13 @@ ResultVal<Kernel::SharedPtr<Directory>> OpenDirectoryFromArchive(ArchiveHandle a | |||
| 167 | const FileSys::Path& path); | 167 | const FileSys::Path& path); |
| 168 | 168 | ||
| 169 | /** | 169 | /** |
| 170 | * Get the free space in an Archive | ||
| 171 | * @param archive_handle Handle to an open Archive object | ||
| 172 | * @return The number of free bytes in the archive | ||
| 173 | */ | ||
| 174 | ResultVal<u64> GetFreeBytesInArchive(ArchiveHandle archive_handle); | ||
| 175 | |||
| 176 | /** | ||
| 170 | * Erases the contents of the physical folder that contains the archive | 177 | * Erases the contents of the physical folder that contains the archive |
| 171 | * identified by the specified id code and path | 178 | * identified by the specified id code and path |
| 172 | * @param id_code The id of the archive to format | 179 | * @param id_code The id of the archive to format |
diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp index ae52083f9..b3fa89302 100644 --- a/src/core/hle/service/fs/fs_user.cpp +++ b/src/core/hle/service/fs/fs_user.cpp | |||
| @@ -497,6 +497,33 @@ static void FormatThisUserSaveData(Service::Interface* self) { | |||
| 497 | } | 497 | } |
| 498 | 498 | ||
| 499 | /** | 499 | /** |
| 500 | * FS_User::GetFreeBytes service function | ||
| 501 | * Inputs: | ||
| 502 | * 0: 0x08120080 | ||
| 503 | * 1: Archive handle low word | ||
| 504 | * 2: Archive handle high word | ||
| 505 | * Outputs: | ||
| 506 | * 1: Result of function, 0 on success, otherwise error code | ||
| 507 | * 2: Free byte count low word | ||
| 508 | * 3: Free byte count high word | ||
| 509 | */ | ||
| 510 | static void GetFreeBytes(Service::Interface* self) { | ||
| 511 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 512 | |||
| 513 | ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[1], cmd_buff[2]); | ||
| 514 | ResultVal<u64> bytes_res = GetFreeBytesInArchive(archive_handle); | ||
| 515 | |||
| 516 | cmd_buff[1] = bytes_res.Code().raw; | ||
| 517 | if (bytes_res.Succeeded()) { | ||
| 518 | cmd_buff[2] = (u32)*bytes_res; | ||
| 519 | cmd_buff[3] = *bytes_res >> 32; | ||
| 520 | } else { | ||
| 521 | cmd_buff[2] = 0; | ||
| 522 | cmd_buff[3] = 0; | ||
| 523 | } | ||
| 524 | } | ||
| 525 | |||
| 526 | /** | ||
| 500 | * FS_User::CreateExtSaveData service function | 527 | * FS_User::CreateExtSaveData service function |
| 501 | * Inputs: | 528 | * Inputs: |
| 502 | * 0 : 0x08510242 | 529 | * 0 : 0x08510242 |
| @@ -700,7 +727,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||
| 700 | {0x080F0180, FormatThisUserSaveData,"FormatThisUserSaveData"}, | 727 | {0x080F0180, FormatThisUserSaveData,"FormatThisUserSaveData"}, |
| 701 | {0x08100200, nullptr, "CreateSystemSaveData"}, | 728 | {0x08100200, nullptr, "CreateSystemSaveData"}, |
| 702 | {0x08110040, nullptr, "DeleteSystemSaveData"}, | 729 | {0x08110040, nullptr, "DeleteSystemSaveData"}, |
| 703 | {0x08120080, nullptr, "GetFreeBytes"}, | 730 | {0x08120080, GetFreeBytes, "GetFreeBytes"}, |
| 704 | {0x08130000, nullptr, "GetCardType"}, | 731 | {0x08130000, nullptr, "GetCardType"}, |
| 705 | {0x08140000, nullptr, "GetSdmcArchiveResource"}, | 732 | {0x08140000, nullptr, "GetSdmcArchiveResource"}, |
| 706 | {0x08150000, nullptr, "GetNandArchiveResource"}, | 733 | {0x08150000, nullptr, "GetNandArchiveResource"}, |
diff --git a/src/core/hle/service/ptm/ptm.cpp b/src/core/hle/service/ptm/ptm.cpp index 2c7d49c9f..22c1093ff 100644 --- a/src/core/hle/service/ptm/ptm.cpp +++ b/src/core/hle/service/ptm/ptm.cpp | |||
| @@ -68,6 +68,18 @@ void GetBatteryChargeState(Service::Interface* self) { | |||
| 68 | LOG_WARNING(Service_PTM, "(STUBBED) called"); | 68 | LOG_WARNING(Service_PTM, "(STUBBED) called"); |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | void GetTotalStepCount(Service::Interface* self) { | ||
| 72 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 73 | |||
| 74 | // TODO: This function is only a stub, | ||
| 75 | // it returns 0 as the total step count | ||
| 76 | |||
| 77 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 78 | cmd_buff[2] = 0; | ||
| 79 | |||
| 80 | LOG_WARNING(Service_PTM, "(STUBBED) called"); | ||
| 81 | } | ||
| 82 | |||
| 71 | void IsLegacyPowerOff(Service::Interface* self) { | 83 | void IsLegacyPowerOff(Service::Interface* self) { |
| 72 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 84 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 73 | 85 | ||
diff --git a/src/core/hle/service/ptm/ptm.h b/src/core/hle/service/ptm/ptm.h index b690003cb..f2e76441f 100644 --- a/src/core/hle/service/ptm/ptm.h +++ b/src/core/hle/service/ptm/ptm.h | |||
| @@ -72,6 +72,14 @@ void GetBatteryLevel(Interface* self); | |||
| 72 | void GetBatteryChargeState(Interface* self); | 72 | void GetBatteryChargeState(Interface* self); |
| 73 | 73 | ||
| 74 | /** | 74 | /** |
| 75 | * PTM::GetTotalStepCount service function | ||
| 76 | * Outputs: | ||
| 77 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 78 | * 2 : Output of function, * = total step count | ||
| 79 | */ | ||
| 80 | void GetTotalStepCount(Interface* self); | ||
| 81 | |||
| 82 | /** | ||
| 75 | * PTM::IsLegacyPowerOff service function | 83 | * PTM::IsLegacyPowerOff service function |
| 76 | * Outputs: | 84 | * Outputs: |
| 77 | * 1: Result code, 0 on success, otherwise error code | 85 | * 1: Result code, 0 on success, otherwise error code |
diff --git a/src/core/hle/service/ptm/ptm_u.cpp b/src/core/hle/service/ptm/ptm_u.cpp index 3f5e9c7c1..09dc38c3e 100644 --- a/src/core/hle/service/ptm/ptm_u.cpp +++ b/src/core/hle/service/ptm/ptm_u.cpp | |||
| @@ -23,7 +23,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||
| 23 | {0x00090000, nullptr, "GetPedometerState"}, | 23 | {0x00090000, nullptr, "GetPedometerState"}, |
| 24 | {0x000A0042, nullptr, "GetStepHistoryEntry"}, | 24 | {0x000A0042, nullptr, "GetStepHistoryEntry"}, |
| 25 | {0x000B00C2, nullptr, "GetStepHistory"}, | 25 | {0x000B00C2, nullptr, "GetStepHistory"}, |
| 26 | {0x000C0000, nullptr, "GetTotalStepCount"}, | 26 | {0x000C0000, GetTotalStepCount, "GetTotalStepCount"}, |
| 27 | {0x000D0040, nullptr, "SetPedometerRecordingMode"}, | 27 | {0x000D0040, nullptr, "SetPedometerRecordingMode"}, |
| 28 | {0x000E0000, nullptr, "GetPedometerRecordingMode"}, | 28 | {0x000E0000, nullptr, "GetPedometerRecordingMode"}, |
| 29 | {0x000F0084, nullptr, "GetStepHistoryAll"}, | 29 | {0x000F0084, nullptr, "GetStepHistoryAll"}, |
diff --git a/src/core/hw/y2r.cpp b/src/core/hw/y2r.cpp index 15f96ced8..48c45564f 100644 --- a/src/core/hw/y2r.cpp +++ b/src/core/hw/y2r.cpp | |||
| @@ -324,7 +324,7 @@ void PerformConversion(ConversionConfiguration& cvt) { | |||
| 324 | 324 | ||
| 325 | u32* output_buffer = reinterpret_cast<u32*>(data_buffer.get()); | 325 | u32* output_buffer = reinterpret_cast<u32*>(data_buffer.get()); |
| 326 | 326 | ||
| 327 | for (int i = 0; i < num_tiles; ++i) { | 327 | for (size_t i = 0; i < num_tiles; ++i) { |
| 328 | int image_strip_width = 0; | 328 | int image_strip_width = 0; |
| 329 | int output_stride = 0; | 329 | int output_stride = 0; |
| 330 | 330 | ||
diff --git a/src/core/loader/3dsx.cpp b/src/core/loader/3dsx.cpp index 111b6a409..8eed6a50a 100644 --- a/src/core/loader/3dsx.cpp +++ b/src/core/loader/3dsx.cpp | |||
| @@ -181,14 +181,14 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr, Shared | |||
| 181 | 181 | ||
| 182 | for (unsigned current_inprogress = 0; current_inprogress < remaining && pos < end_pos; current_inprogress++) { | 182 | for (unsigned current_inprogress = 0; current_inprogress < remaining && pos < end_pos; current_inprogress++) { |
| 183 | const auto& table = reloc_table[current_inprogress]; | 183 | const auto& table = reloc_table[current_inprogress]; |
| 184 | LOG_TRACE(Loader, "(t=%d,skip=%u,patch=%u)\n", current_segment_reloc_table, | 184 | LOG_TRACE(Loader, "(t=%d,skip=%u,patch=%u)", current_segment_reloc_table, |
| 185 | (u32)table.skip, (u32)table.patch); | 185 | (u32)table.skip, (u32)table.patch); |
| 186 | pos += table.skip; | 186 | pos += table.skip; |
| 187 | s32 num_patches = table.patch; | 187 | s32 num_patches = table.patch; |
| 188 | while (0 < num_patches && pos < end_pos) { | 188 | while (0 < num_patches && pos < end_pos) { |
| 189 | u32 in_addr = (u8*)pos - program_image.data(); | 189 | u32 in_addr = (u8*)pos - program_image.data(); |
| 190 | u32 addr = TranslateAddr(*pos, &loadinfo, offsets); | 190 | u32 addr = TranslateAddr(*pos, &loadinfo, offsets); |
| 191 | LOG_TRACE(Loader, "Patching %08X <-- rel(%08X,%d) (%08X)\n", | 191 | LOG_TRACE(Loader, "Patching %08X <-- rel(%08X,%d) (%08X)", |
| 192 | base_addr + in_addr, addr, current_segment_reloc_table, *pos); | 192 | base_addr + in_addr, addr, current_segment_reloc_table, *pos); |
| 193 | switch (current_segment_reloc_table) { | 193 | switch (current_segment_reloc_table) { |
| 194 | case 0: | 194 | case 0: |
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index 8de95dacf..a7f2715ba 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h | |||
| @@ -71,6 +71,7 @@ enum class ResultStatus { | |||
| 71 | ErrorNotUsed, | 71 | ErrorNotUsed, |
| 72 | ErrorAlreadyLoaded, | 72 | ErrorAlreadyLoaded, |
| 73 | ErrorMemoryAllocationFailed, | 73 | ErrorMemoryAllocationFailed, |
| 74 | ErrorEncrypted, | ||
| 74 | }; | 75 | }; |
| 75 | 76 | ||
| 76 | static inline u32 MakeMagic(char a, char b, char c, char d) { | 77 | static inline u32 MakeMagic(char a, char b, char c, char d) { |
diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp index 094d74100..68b3f546e 100644 --- a/src/core/loader/ncch.cpp +++ b/src/core/loader/ncch.cpp | |||
| @@ -128,9 +128,8 @@ ResultStatus AppLoader_NCCH::LoadExec() { | |||
| 128 | if (ResultStatus::Success == ReadCode(code)) { | 128 | if (ResultStatus::Success == ReadCode(code)) { |
| 129 | std::string process_name = Common::StringFromFixedZeroTerminatedBuffer( | 129 | std::string process_name = Common::StringFromFixedZeroTerminatedBuffer( |
| 130 | (const char*)exheader_header.codeset_info.name, 8); | 130 | (const char*)exheader_header.codeset_info.name, 8); |
| 131 | u64 program_id = *reinterpret_cast<u64_le const*>(&ncch_header.program_id[0]); | ||
| 132 | 131 | ||
| 133 | SharedPtr<CodeSet> codeset = CodeSet::Create(process_name, program_id); | 132 | SharedPtr<CodeSet> codeset = CodeSet::Create(process_name, ncch_header.program_id); |
| 134 | 133 | ||
| 135 | codeset->code.offset = 0; | 134 | codeset->code.offset = 0; |
| 136 | codeset->code.addr = exheader_header.codeset_info.text.address; | 135 | codeset->code.addr = exheader_header.codeset_info.text.address; |
| @@ -266,6 +265,11 @@ ResultStatus AppLoader_NCCH::Load() { | |||
| 266 | LOG_DEBUG(Loader, "Thread priority: 0x%X" , priority); | 265 | LOG_DEBUG(Loader, "Thread priority: 0x%X" , priority); |
| 267 | LOG_DEBUG(Loader, "Resource limit category: %d" , resource_limit_category); | 266 | LOG_DEBUG(Loader, "Resource limit category: %d" , resource_limit_category); |
| 268 | 267 | ||
| 268 | if (exheader_header.arm11_system_local_caps.program_id != ncch_header.program_id) { | ||
| 269 | LOG_ERROR(Loader, "ExHeader Program ID mismatch: the ROM is probably encrypted."); | ||
| 270 | return ResultStatus::ErrorEncrypted; | ||
| 271 | } | ||
| 272 | |||
| 269 | // Read ExeFS... | 273 | // Read ExeFS... |
| 270 | 274 | ||
| 271 | exefs_offset = ncch_header.exefs_offset * kBlockSize; | 275 | exefs_offset = ncch_header.exefs_offset * kBlockSize; |
diff --git a/src/core/loader/ncch.h b/src/core/loader/ncch.h index d875e4cf3..ca6772a78 100644 --- a/src/core/loader/ncch.h +++ b/src/core/loader/ncch.h | |||
| @@ -17,31 +17,31 @@ | |||
| 17 | 17 | ||
| 18 | struct NCCH_Header { | 18 | struct NCCH_Header { |
| 19 | u8 signature[0x100]; | 19 | u8 signature[0x100]; |
| 20 | u32 magic; | 20 | u32_le magic; |
| 21 | u32 content_size; | 21 | u32_le content_size; |
| 22 | u8 partition_id[8]; | 22 | u8 partition_id[8]; |
| 23 | u16 maker_code; | 23 | u16_le maker_code; |
| 24 | u16 version; | 24 | u16_le version; |
| 25 | u8 reserved_0[4]; | 25 | u8 reserved_0[4]; |
| 26 | u8 program_id[8]; | 26 | u64_le program_id; |
| 27 | u8 reserved_1[0x10]; | 27 | u8 reserved_1[0x10]; |
| 28 | u8 logo_region_hash[0x20]; | 28 | u8 logo_region_hash[0x20]; |
| 29 | u8 product_code[0x10]; | 29 | u8 product_code[0x10]; |
| 30 | u8 extended_header_hash[0x20]; | 30 | u8 extended_header_hash[0x20]; |
| 31 | u32 extended_header_size; | 31 | u32_le extended_header_size; |
| 32 | u8 reserved_2[4]; | 32 | u8 reserved_2[4]; |
| 33 | u8 flags[8]; | 33 | u8 flags[8]; |
| 34 | u32 plain_region_offset; | 34 | u32_le plain_region_offset; |
| 35 | u32 plain_region_size; | 35 | u32_le plain_region_size; |
| 36 | u32 logo_region_offset; | 36 | u32_le logo_region_offset; |
| 37 | u32 logo_region_size; | 37 | u32_le logo_region_size; |
| 38 | u32 exefs_offset; | 38 | u32_le exefs_offset; |
| 39 | u32 exefs_size; | 39 | u32_le exefs_size; |
| 40 | u32 exefs_hash_region_size; | 40 | u32_le exefs_hash_region_size; |
| 41 | u8 reserved_3[4]; | 41 | u8 reserved_3[4]; |
| 42 | u32 romfs_offset; | 42 | u32_le romfs_offset; |
| 43 | u32 romfs_size; | 43 | u32_le romfs_size; |
| 44 | u32 romfs_hash_region_size; | 44 | u32_le romfs_hash_region_size; |
| 45 | u8 reserved_4[4]; | 45 | u8 reserved_4[4]; |
| 46 | u8 exefs_super_block_hash[0x20]; | 46 | u8 exefs_super_block_hash[0x20]; |
| 47 | u8 romfs_super_block_hash[0x20]; | 47 | u8 romfs_super_block_hash[0x20]; |
| @@ -109,8 +109,8 @@ struct ExHeader_StorageInfo { | |||
| 109 | }; | 109 | }; |
| 110 | 110 | ||
| 111 | struct ExHeader_ARM11_SystemLocalCaps { | 111 | struct ExHeader_ARM11_SystemLocalCaps { |
| 112 | u8 program_id[8]; | 112 | u64_le program_id; |
| 113 | u32 core_version; | 113 | u32_le core_version; |
| 114 | u8 reserved_flags[2]; | 114 | u8 reserved_flags[2]; |
| 115 | union { | 115 | union { |
| 116 | u8 flags0; | 116 | u8 flags0; |
diff --git a/src/core/memory.cpp b/src/core/memory.cpp index b80795e0c..fc79c3ee9 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp | |||
| @@ -26,9 +26,9 @@ enum class PageType { | |||
| 26 | }; | 26 | }; |
| 27 | 27 | ||
| 28 | /** | 28 | /** |
| 29 | * A (reasonably) fast way of allowing switchable and remmapable process address spaces. It loosely | 29 | * A (reasonably) fast way of allowing switchable and remappable process address spaces. It loosely |
| 30 | * mimics the way a real CPU page table works, but instead is optimized for minimal decoding and | 30 | * mimics the way a real CPU page table works, but instead is optimized for minimal decoding and |
| 31 | * fetching requirements when acessing. In the usual case of an access to regular memory, it only | 31 | * fetching requirements when accessing. In the usual case of an access to regular memory, it only |
| 32 | * requires an indexed fetch and a check for NULL. | 32 | * requires an indexed fetch and a check for NULL. |
| 33 | */ | 33 | */ |
| 34 | struct PageTable { | 34 | struct PageTable { |
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 8c9d76ab4..2a924f4ad 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | set(SRCS | 1 | set(SRCS |
| 2 | renderer_opengl/gl_rasterizer.cpp | 2 | renderer_opengl/gl_rasterizer.cpp |
| 3 | renderer_opengl/gl_rasterizer_cache.cpp | 3 | renderer_opengl/gl_rasterizer_cache.cpp |
| 4 | renderer_opengl/gl_shader_gen.cpp | ||
| 4 | renderer_opengl/gl_shader_util.cpp | 5 | renderer_opengl/gl_shader_util.cpp |
| 5 | renderer_opengl/gl_state.cpp | 6 | renderer_opengl/gl_state.cpp |
| 6 | renderer_opengl/renderer_opengl.cpp | 7 | renderer_opengl/renderer_opengl.cpp |
| @@ -21,8 +22,8 @@ set(HEADERS | |||
| 21 | renderer_opengl/gl_rasterizer.h | 22 | renderer_opengl/gl_rasterizer.h |
| 22 | renderer_opengl/gl_rasterizer_cache.h | 23 | renderer_opengl/gl_rasterizer_cache.h |
| 23 | renderer_opengl/gl_resource_manager.h | 24 | renderer_opengl/gl_resource_manager.h |
| 25 | renderer_opengl/gl_shader_gen.h | ||
| 24 | renderer_opengl/gl_shader_util.h | 26 | renderer_opengl/gl_shader_util.h |
| 25 | renderer_opengl/gl_shaders.h | ||
| 26 | renderer_opengl/gl_state.h | 27 | renderer_opengl/gl_state.h |
| 27 | renderer_opengl/pica_to_gl.h | 28 | renderer_opengl/pica_to_gl.h |
| 28 | renderer_opengl/renderer_opengl.h | 29 | renderer_opengl/renderer_opengl.h |
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp index 47afd8938..bd1b09a4b 100644 --- a/src/video_core/command_processor.cpp +++ b/src/video_core/command_processor.cpp | |||
| @@ -157,6 +157,8 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { | |||
| 157 | 157 | ||
| 158 | // TODO: What happens if a loader overwrites a previous one's data? | 158 | // TODO: What happens if a loader overwrites a previous one's data? |
| 159 | for (unsigned component = 0; component < loader_config.component_count; ++component) { | 159 | for (unsigned component = 0; component < loader_config.component_count; ++component) { |
| 160 | if (component >= 12) | ||
| 161 | LOG_ERROR(HW_GPU, "Overflow in the vertex attribute loader %u trying to load component %u", loader, component); | ||
| 160 | u32 attribute_index = loader_config.GetComponent(component); | 162 | u32 attribute_index = loader_config.GetComponent(component); |
| 161 | vertex_attribute_sources[attribute_index] = load_address; | 163 | vertex_attribute_sources[attribute_index] = load_address; |
| 162 | vertex_attribute_strides[attribute_index] = static_cast<u32>(loader_config.byte_count); | 164 | vertex_attribute_strides[attribute_index] = static_cast<u32>(loader_config.byte_count); |
diff --git a/src/video_core/debug_utils/debug_utils.cpp b/src/video_core/debug_utils/debug_utils.cpp index aa1f1484c..f1cfa9361 100644 --- a/src/video_core/debug_utils/debug_utils.cpp +++ b/src/video_core/debug_utils/debug_utils.cpp | |||
| @@ -641,7 +641,7 @@ void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) { | |||
| 641 | // Initialize write structure | 641 | // Initialize write structure |
| 642 | png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); | 642 | png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); |
| 643 | if (png_ptr == nullptr) { | 643 | if (png_ptr == nullptr) { |
| 644 | LOG_ERROR(Debug_GPU, "Could not allocate write struct\n"); | 644 | LOG_ERROR(Debug_GPU, "Could not allocate write struct"); |
| 645 | goto finalise; | 645 | goto finalise; |
| 646 | 646 | ||
| 647 | } | 647 | } |
| @@ -649,13 +649,13 @@ void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) { | |||
| 649 | // Initialize info structure | 649 | // Initialize info structure |
| 650 | info_ptr = png_create_info_struct(png_ptr); | 650 | info_ptr = png_create_info_struct(png_ptr); |
| 651 | if (info_ptr == nullptr) { | 651 | if (info_ptr == nullptr) { |
| 652 | LOG_ERROR(Debug_GPU, "Could not allocate info struct\n"); | 652 | LOG_ERROR(Debug_GPU, "Could not allocate info struct"); |
| 653 | goto finalise; | 653 | goto finalise; |
| 654 | } | 654 | } |
| 655 | 655 | ||
| 656 | // Setup Exception handling | 656 | // Setup Exception handling |
| 657 | if (setjmp(png_jmpbuf(png_ptr))) { | 657 | if (setjmp(png_jmpbuf(png_ptr))) { |
| 658 | LOG_ERROR(Debug_GPU, "Error during png creation\n"); | 658 | LOG_ERROR(Debug_GPU, "Error during png creation"); |
| 659 | goto finalise; | 659 | goto finalise; |
| 660 | } | 660 | } |
| 661 | 661 | ||
diff --git a/src/video_core/pica.h b/src/video_core/pica.h index ff81b409d..2f1b2dec4 100644 --- a/src/video_core/pica.h +++ b/src/video_core/pica.h | |||
| @@ -317,6 +317,7 @@ struct Regs { | |||
| 317 | }; | 317 | }; |
| 318 | 318 | ||
| 319 | union { | 319 | union { |
| 320 | u32 sources_raw; | ||
| 320 | BitField< 0, 4, Source> color_source1; | 321 | BitField< 0, 4, Source> color_source1; |
| 321 | BitField< 4, 4, Source> color_source2; | 322 | BitField< 4, 4, Source> color_source2; |
| 322 | BitField< 8, 4, Source> color_source3; | 323 | BitField< 8, 4, Source> color_source3; |
| @@ -326,6 +327,7 @@ struct Regs { | |||
| 326 | }; | 327 | }; |
| 327 | 328 | ||
| 328 | union { | 329 | union { |
| 330 | u32 modifiers_raw; | ||
| 329 | BitField< 0, 4, ColorModifier> color_modifier1; | 331 | BitField< 0, 4, ColorModifier> color_modifier1; |
| 330 | BitField< 4, 4, ColorModifier> color_modifier2; | 332 | BitField< 4, 4, ColorModifier> color_modifier2; |
| 331 | BitField< 8, 4, ColorModifier> color_modifier3; | 333 | BitField< 8, 4, ColorModifier> color_modifier3; |
| @@ -335,6 +337,7 @@ struct Regs { | |||
| 335 | }; | 337 | }; |
| 336 | 338 | ||
| 337 | union { | 339 | union { |
| 340 | u32 ops_raw; | ||
| 338 | BitField< 0, 4, Operation> color_op; | 341 | BitField< 0, 4, Operation> color_op; |
| 339 | BitField<16, 4, Operation> alpha_op; | 342 | BitField<16, 4, Operation> alpha_op; |
| 340 | }; | 343 | }; |
| @@ -348,6 +351,7 @@ struct Regs { | |||
| 348 | }; | 351 | }; |
| 349 | 352 | ||
| 350 | union { | 353 | union { |
| 354 | u32 scales_raw; | ||
| 351 | BitField< 0, 2, u32> color_scale; | 355 | BitField< 0, 2, u32> color_scale; |
| 352 | BitField<16, 2, u32> alpha_scale; | 356 | BitField<16, 2, u32> alpha_scale; |
| 353 | }; | 357 | }; |
diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp index 7abf60292..226fad783 100644 --- a/src/video_core/rasterizer.cpp +++ b/src/video_core/rasterizer.cpp | |||
| @@ -462,7 +462,7 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0, | |||
| 462 | } | 462 | } |
| 463 | 463 | ||
| 464 | default: | 464 | default: |
| 465 | LOG_ERROR(HW_GPU, "Unknown texture coordinate wrapping mode %x\n", (int)mode); | 465 | LOG_ERROR(HW_GPU, "Unknown texture coordinate wrapping mode %x", (int)mode); |
| 466 | UNIMPLEMENTED(); | 466 | UNIMPLEMENTED(); |
| 467 | return 0; | 467 | return 0; |
| 468 | } | 468 | } |
| @@ -541,7 +541,7 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0, | |||
| 541 | return combiner_output; | 541 | return combiner_output; |
| 542 | 542 | ||
| 543 | default: | 543 | default: |
| 544 | LOG_ERROR(HW_GPU, "Unknown color combiner source %d\n", (int)source); | 544 | LOG_ERROR(HW_GPU, "Unknown color combiner source %d", (int)source); |
| 545 | UNIMPLEMENTED(); | 545 | UNIMPLEMENTED(); |
| 546 | return {0, 0, 0, 0}; | 546 | return {0, 0, 0, 0}; |
| 547 | } | 547 | } |
| @@ -679,7 +679,7 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0, | |||
| 679 | return { (u8)result, (u8)result, (u8)result }; | 679 | return { (u8)result, (u8)result, (u8)result }; |
| 680 | } | 680 | } |
| 681 | default: | 681 | default: |
| 682 | LOG_ERROR(HW_GPU, "Unknown color combiner operation %d\n", (int)op); | 682 | LOG_ERROR(HW_GPU, "Unknown color combiner operation %d", (int)op); |
| 683 | UNIMPLEMENTED(); | 683 | UNIMPLEMENTED(); |
| 684 | return {0, 0, 0}; | 684 | return {0, 0, 0}; |
| 685 | } | 685 | } |
| @@ -716,7 +716,7 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0, | |||
| 716 | return (std::min(255, (input[0] + input[1])) * input[2]) / 255; | 716 | return (std::min(255, (input[0] + input[1])) * input[2]) / 255; |
| 717 | 717 | ||
| 718 | default: | 718 | default: |
| 719 | LOG_ERROR(HW_GPU, "Unknown alpha combiner operation %d\n", (int)op); | 719 | LOG_ERROR(HW_GPU, "Unknown alpha combiner operation %d", (int)op); |
| 720 | UNIMPLEMENTED(); | 720 | UNIMPLEMENTED(); |
| 721 | return 0; | 721 | return 0; |
| 722 | } | 722 | } |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 50eb157a5..d1def2f3b 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -8,6 +8,8 @@ | |||
| 8 | #include <glad/glad.h> | 8 | #include <glad/glad.h> |
| 9 | 9 | ||
| 10 | #include "common/color.h" | 10 | #include "common/color.h" |
| 11 | #include "common/file_util.h" | ||
| 12 | #include "common/make_unique.h" | ||
| 11 | #include "common/math_util.h" | 13 | #include "common/math_util.h" |
| 12 | #include "common/microprofile.h" | 14 | #include "common/microprofile.h" |
| 13 | #include "common/profiler.h" | 15 | #include "common/profiler.h" |
| @@ -19,7 +21,7 @@ | |||
| 19 | #include "video_core/pica.h" | 21 | #include "video_core/pica.h" |
| 20 | #include "video_core/utils.h" | 22 | #include "video_core/utils.h" |
| 21 | #include "video_core/renderer_opengl/gl_rasterizer.h" | 23 | #include "video_core/renderer_opengl/gl_rasterizer.h" |
| 22 | #include "video_core/renderer_opengl/gl_shaders.h" | 24 | #include "video_core/renderer_opengl/gl_shader_gen.h" |
| 23 | #include "video_core/renderer_opengl/gl_shader_util.h" | 25 | #include "video_core/renderer_opengl/gl_shader_util.h" |
| 24 | #include "video_core/renderer_opengl/pica_to_gl.h" | 26 | #include "video_core/renderer_opengl/pica_to_gl.h" |
| 25 | 27 | ||
| @@ -38,38 +40,8 @@ RasterizerOpenGL::RasterizerOpenGL() : last_fb_color_addr(0), last_fb_depth_addr | |||
| 38 | RasterizerOpenGL::~RasterizerOpenGL() { } | 40 | RasterizerOpenGL::~RasterizerOpenGL() { } |
| 39 | 41 | ||
| 40 | void RasterizerOpenGL::InitObjects() { | 42 | void RasterizerOpenGL::InitObjects() { |
| 41 | // Create the hardware shader program and get attrib/uniform locations | ||
| 42 | shader.Create(GLShaders::g_vertex_shader_hw, GLShaders::g_fragment_shader_hw); | ||
| 43 | attrib_position = glGetAttribLocation(shader.handle, "vert_position"); | ||
| 44 | attrib_color = glGetAttribLocation(shader.handle, "vert_color"); | ||
| 45 | attrib_texcoords = glGetAttribLocation(shader.handle, "vert_texcoords"); | ||
| 46 | |||
| 47 | uniform_alphatest_enabled = glGetUniformLocation(shader.handle, "alphatest_enabled"); | ||
| 48 | uniform_alphatest_func = glGetUniformLocation(shader.handle, "alphatest_func"); | ||
| 49 | uniform_alphatest_ref = glGetUniformLocation(shader.handle, "alphatest_ref"); | ||
| 50 | |||
| 51 | uniform_tex = glGetUniformLocation(shader.handle, "tex"); | ||
| 52 | |||
| 53 | uniform_tev_combiner_buffer_color = glGetUniformLocation(shader.handle, "tev_combiner_buffer_color"); | ||
| 54 | |||
| 55 | const auto tev_stages = Pica::g_state.regs.GetTevStages(); | ||
| 56 | for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size(); ++tev_stage_index) { | ||
| 57 | auto& uniform_tev_cfg = uniform_tev_cfgs[tev_stage_index]; | ||
| 58 | |||
| 59 | std::string tev_ref_str = "tev_cfgs[" + std::to_string(tev_stage_index) + "]"; | ||
| 60 | uniform_tev_cfg.enabled = glGetUniformLocation(shader.handle, (tev_ref_str + ".enabled").c_str()); | ||
| 61 | uniform_tev_cfg.color_sources = glGetUniformLocation(shader.handle, (tev_ref_str + ".color_sources").c_str()); | ||
| 62 | uniform_tev_cfg.alpha_sources = glGetUniformLocation(shader.handle, (tev_ref_str + ".alpha_sources").c_str()); | ||
| 63 | uniform_tev_cfg.color_modifiers = glGetUniformLocation(shader.handle, (tev_ref_str + ".color_modifiers").c_str()); | ||
| 64 | uniform_tev_cfg.alpha_modifiers = glGetUniformLocation(shader.handle, (tev_ref_str + ".alpha_modifiers").c_str()); | ||
| 65 | uniform_tev_cfg.color_alpha_op = glGetUniformLocation(shader.handle, (tev_ref_str + ".color_alpha_op").c_str()); | ||
| 66 | uniform_tev_cfg.color_alpha_multiplier = glGetUniformLocation(shader.handle, (tev_ref_str + ".color_alpha_multiplier").c_str()); | ||
| 67 | uniform_tev_cfg.const_color = glGetUniformLocation(shader.handle, (tev_ref_str + ".const_color").c_str()); | ||
| 68 | uniform_tev_cfg.updates_combiner_buffer_color_alpha = glGetUniformLocation(shader.handle, (tev_ref_str + ".updates_combiner_buffer_color_alpha").c_str()); | ||
| 69 | } | ||
| 70 | |||
| 71 | // Create sampler objects | 43 | // Create sampler objects |
| 72 | for (int i = 0; i < texture_samplers.size(); ++i) { | 44 | for (size_t i = 0; i < texture_samplers.size(); ++i) { |
| 73 | texture_samplers[i].Create(); | 45 | texture_samplers[i].Create(); |
| 74 | state.texture_units[i].sampler = texture_samplers[i].sampler.handle; | 46 | state.texture_units[i].sampler = texture_samplers[i].sampler.handle; |
| 75 | } | 47 | } |
| @@ -78,29 +50,25 @@ void RasterizerOpenGL::InitObjects() { | |||
| 78 | vertex_buffer.Create(); | 50 | vertex_buffer.Create(); |
| 79 | vertex_array.Create(); | 51 | vertex_array.Create(); |
| 80 | 52 | ||
| 81 | // Update OpenGL state | ||
| 82 | state.draw.vertex_array = vertex_array.handle; | 53 | state.draw.vertex_array = vertex_array.handle; |
| 83 | state.draw.vertex_buffer = vertex_buffer.handle; | 54 | state.draw.vertex_buffer = vertex_buffer.handle; |
| 84 | state.draw.shader_program = shader.handle; | ||
| 85 | |||
| 86 | state.Apply(); | 55 | state.Apply(); |
| 87 | 56 | ||
| 88 | // Set the texture samplers to correspond to different texture units | ||
| 89 | glUniform1i(uniform_tex, 0); | ||
| 90 | glUniform1i(uniform_tex + 1, 1); | ||
| 91 | glUniform1i(uniform_tex + 2, 2); | ||
| 92 | |||
| 93 | // Set vertex attributes | 57 | // Set vertex attributes |
| 94 | glVertexAttribPointer(attrib_position, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, position)); | 58 | glVertexAttribPointer(GLShader::ATTRIBUTE_POSITION, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, position)); |
| 95 | glVertexAttribPointer(attrib_color, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, color)); | 59 | glEnableVertexAttribArray(GLShader::ATTRIBUTE_POSITION); |
| 96 | glVertexAttribPointer(attrib_texcoords, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord0)); | 60 | |
| 97 | glVertexAttribPointer(attrib_texcoords + 1, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord1)); | 61 | glVertexAttribPointer(GLShader::ATTRIBUTE_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, color)); |
| 98 | glVertexAttribPointer(attrib_texcoords + 2, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord2)); | 62 | glEnableVertexAttribArray(GLShader::ATTRIBUTE_COLOR); |
| 99 | glEnableVertexAttribArray(attrib_position); | 63 | |
| 100 | glEnableVertexAttribArray(attrib_color); | 64 | glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORD0, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord0)); |
| 101 | glEnableVertexAttribArray(attrib_texcoords); | 65 | glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORD1, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord1)); |
| 102 | glEnableVertexAttribArray(attrib_texcoords + 1); | 66 | glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORD2, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord2)); |
| 103 | glEnableVertexAttribArray(attrib_texcoords + 2); | 67 | glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORD0); |
| 68 | glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORD1); | ||
| 69 | glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORD2); | ||
| 70 | |||
| 71 | SetShader(); | ||
| 104 | 72 | ||
| 105 | // Create textures for OGL framebuffer that will be rendered to, initially 1x1 to succeed in framebuffer creation | 73 | // Create textures for OGL framebuffer that will be rendered to, initially 1x1 to succeed in framebuffer creation |
| 106 | fb_color_texture.texture.Create(); | 74 | fb_color_texture.texture.Create(); |
| @@ -150,61 +118,15 @@ void RasterizerOpenGL::InitObjects() { | |||
| 150 | } | 118 | } |
| 151 | 119 | ||
| 152 | void RasterizerOpenGL::Reset() { | 120 | void RasterizerOpenGL::Reset() { |
| 153 | const auto& regs = Pica::g_state.regs; | ||
| 154 | |||
| 155 | SyncCullMode(); | 121 | SyncCullMode(); |
| 156 | SyncBlendEnabled(); | 122 | SyncBlendEnabled(); |
| 157 | SyncBlendFuncs(); | 123 | SyncBlendFuncs(); |
| 158 | SyncBlendColor(); | 124 | SyncBlendColor(); |
| 159 | SyncAlphaTest(); | ||
| 160 | SyncLogicOp(); | 125 | SyncLogicOp(); |
| 161 | SyncStencilTest(); | 126 | SyncStencilTest(); |
| 162 | SyncDepthTest(); | 127 | SyncDepthTest(); |
| 163 | 128 | ||
| 164 | // TEV stage 0 | 129 | SetShader(); |
| 165 | SyncTevSources(0, regs.tev_stage0); | ||
| 166 | SyncTevModifiers(0, regs.tev_stage0); | ||
| 167 | SyncTevOps(0, regs.tev_stage0); | ||
| 168 | SyncTevColor(0, regs.tev_stage0); | ||
| 169 | SyncTevMultipliers(0, regs.tev_stage0); | ||
| 170 | |||
| 171 | // TEV stage 1 | ||
| 172 | SyncTevSources(1, regs.tev_stage1); | ||
| 173 | SyncTevModifiers(1, regs.tev_stage1); | ||
| 174 | SyncTevOps(1, regs.tev_stage1); | ||
| 175 | SyncTevColor(1, regs.tev_stage1); | ||
| 176 | SyncTevMultipliers(1, regs.tev_stage1); | ||
| 177 | |||
| 178 | // TEV stage 2 | ||
| 179 | SyncTevSources(2, regs.tev_stage2); | ||
| 180 | SyncTevModifiers(2, regs.tev_stage2); | ||
| 181 | SyncTevOps(2, regs.tev_stage2); | ||
| 182 | SyncTevColor(2, regs.tev_stage2); | ||
| 183 | SyncTevMultipliers(2, regs.tev_stage2); | ||
| 184 | |||
| 185 | // TEV stage 3 | ||
| 186 | SyncTevSources(3, regs.tev_stage3); | ||
| 187 | SyncTevModifiers(3, regs.tev_stage3); | ||
| 188 | SyncTevOps(3, regs.tev_stage3); | ||
| 189 | SyncTevColor(3, regs.tev_stage3); | ||
| 190 | SyncTevMultipliers(3, regs.tev_stage3); | ||
| 191 | |||
| 192 | // TEV stage 4 | ||
| 193 | SyncTevSources(4, regs.tev_stage4); | ||
| 194 | SyncTevModifiers(4, regs.tev_stage4); | ||
| 195 | SyncTevOps(4, regs.tev_stage4); | ||
| 196 | SyncTevColor(4, regs.tev_stage4); | ||
| 197 | SyncTevMultipliers(4, regs.tev_stage4); | ||
| 198 | |||
| 199 | // TEV stage 5 | ||
| 200 | SyncTevSources(5, regs.tev_stage5); | ||
| 201 | SyncTevModifiers(5, regs.tev_stage5); | ||
| 202 | SyncTevOps(5, regs.tev_stage5); | ||
| 203 | SyncTevColor(5, regs.tev_stage5); | ||
| 204 | SyncTevMultipliers(5, regs.tev_stage5); | ||
| 205 | |||
| 206 | SyncCombinerColor(); | ||
| 207 | SyncCombinerWriteFlags(); | ||
| 208 | 130 | ||
| 209 | res_cache.FullFlush(); | 131 | res_cache.FullFlush(); |
| 210 | } | 132 | } |
| @@ -221,6 +143,11 @@ void RasterizerOpenGL::DrawTriangles() { | |||
| 221 | SyncFramebuffer(); | 143 | SyncFramebuffer(); |
| 222 | SyncDrawState(); | 144 | SyncDrawState(); |
| 223 | 145 | ||
| 146 | if (state.draw.shader_dirty) { | ||
| 147 | SetShader(); | ||
| 148 | state.draw.shader_dirty = false; | ||
| 149 | } | ||
| 150 | |||
| 224 | glBufferData(GL_ARRAY_BUFFER, vertex_batch.size() * sizeof(HardwareVertex), vertex_batch.data(), GL_STREAM_DRAW); | 151 | glBufferData(GL_ARRAY_BUFFER, vertex_batch.size() * sizeof(HardwareVertex), vertex_batch.data(), GL_STREAM_DRAW); |
| 225 | glDrawArrays(GL_TRIANGLES, 0, (GLsizei)vertex_batch.size()); | 152 | glDrawArrays(GL_TRIANGLES, 0, (GLsizei)vertex_batch.size()); |
| 226 | 153 | ||
| @@ -272,6 +199,7 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { | |||
| 272 | // Alpha test | 199 | // Alpha test |
| 273 | case PICA_REG_INDEX(output_merger.alpha_test): | 200 | case PICA_REG_INDEX(output_merger.alpha_test): |
| 274 | SyncAlphaTest(); | 201 | SyncAlphaTest(); |
| 202 | state.draw.shader_dirty = true; | ||
| 275 | break; | 203 | break; |
| 276 | 204 | ||
| 277 | // Stencil test | 205 | // Stencil test |
| @@ -290,117 +218,57 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { | |||
| 290 | SyncLogicOp(); | 218 | SyncLogicOp(); |
| 291 | break; | 219 | break; |
| 292 | 220 | ||
| 293 | // TEV stage 0 | 221 | // TEV stages |
| 294 | case PICA_REG_INDEX(tev_stage0.color_source1): | 222 | case PICA_REG_INDEX(tev_stage0.color_source1): |
| 295 | SyncTevSources(0, regs.tev_stage0); | ||
| 296 | break; | ||
| 297 | case PICA_REG_INDEX(tev_stage0.color_modifier1): | 223 | case PICA_REG_INDEX(tev_stage0.color_modifier1): |
| 298 | SyncTevModifiers(0, regs.tev_stage0); | ||
| 299 | break; | ||
| 300 | case PICA_REG_INDEX(tev_stage0.color_op): | 224 | case PICA_REG_INDEX(tev_stage0.color_op): |
| 301 | SyncTevOps(0, regs.tev_stage0); | ||
| 302 | break; | ||
| 303 | case PICA_REG_INDEX(tev_stage0.const_r): | ||
| 304 | SyncTevColor(0, regs.tev_stage0); | ||
| 305 | break; | ||
| 306 | case PICA_REG_INDEX(tev_stage0.color_scale): | 225 | case PICA_REG_INDEX(tev_stage0.color_scale): |
| 307 | SyncTevMultipliers(0, regs.tev_stage0); | ||
| 308 | break; | ||
| 309 | |||
| 310 | // TEV stage 1 | ||
| 311 | case PICA_REG_INDEX(tev_stage1.color_source1): | 226 | case PICA_REG_INDEX(tev_stage1.color_source1): |
| 312 | SyncTevSources(1, regs.tev_stage1); | ||
| 313 | break; | ||
| 314 | case PICA_REG_INDEX(tev_stage1.color_modifier1): | 227 | case PICA_REG_INDEX(tev_stage1.color_modifier1): |
| 315 | SyncTevModifiers(1, regs.tev_stage1); | ||
| 316 | break; | ||
| 317 | case PICA_REG_INDEX(tev_stage1.color_op): | 228 | case PICA_REG_INDEX(tev_stage1.color_op): |
| 318 | SyncTevOps(1, regs.tev_stage1); | ||
| 319 | break; | ||
| 320 | case PICA_REG_INDEX(tev_stage1.const_r): | ||
| 321 | SyncTevColor(1, regs.tev_stage1); | ||
| 322 | break; | ||
| 323 | case PICA_REG_INDEX(tev_stage1.color_scale): | 229 | case PICA_REG_INDEX(tev_stage1.color_scale): |
| 324 | SyncTevMultipliers(1, regs.tev_stage1); | ||
| 325 | break; | ||
| 326 | |||
| 327 | // TEV stage 2 | ||
| 328 | case PICA_REG_INDEX(tev_stage2.color_source1): | 230 | case PICA_REG_INDEX(tev_stage2.color_source1): |
| 329 | SyncTevSources(2, regs.tev_stage2); | ||
| 330 | break; | ||
| 331 | case PICA_REG_INDEX(tev_stage2.color_modifier1): | 231 | case PICA_REG_INDEX(tev_stage2.color_modifier1): |
| 332 | SyncTevModifiers(2, regs.tev_stage2); | ||
| 333 | break; | ||
| 334 | case PICA_REG_INDEX(tev_stage2.color_op): | 232 | case PICA_REG_INDEX(tev_stage2.color_op): |
| 335 | SyncTevOps(2, regs.tev_stage2); | ||
| 336 | break; | ||
| 337 | case PICA_REG_INDEX(tev_stage2.const_r): | ||
| 338 | SyncTevColor(2, regs.tev_stage2); | ||
| 339 | break; | ||
| 340 | case PICA_REG_INDEX(tev_stage2.color_scale): | 233 | case PICA_REG_INDEX(tev_stage2.color_scale): |
| 341 | SyncTevMultipliers(2, regs.tev_stage2); | ||
| 342 | break; | ||
| 343 | |||
| 344 | // TEV stage 3 | ||
| 345 | case PICA_REG_INDEX(tev_stage3.color_source1): | 234 | case PICA_REG_INDEX(tev_stage3.color_source1): |
| 346 | SyncTevSources(3, regs.tev_stage3); | ||
| 347 | break; | ||
| 348 | case PICA_REG_INDEX(tev_stage3.color_modifier1): | 235 | case PICA_REG_INDEX(tev_stage3.color_modifier1): |
| 349 | SyncTevModifiers(3, regs.tev_stage3); | ||
| 350 | break; | ||
| 351 | case PICA_REG_INDEX(tev_stage3.color_op): | 236 | case PICA_REG_INDEX(tev_stage3.color_op): |
| 352 | SyncTevOps(3, regs.tev_stage3); | ||
| 353 | break; | ||
| 354 | case PICA_REG_INDEX(tev_stage3.const_r): | ||
| 355 | SyncTevColor(3, regs.tev_stage3); | ||
| 356 | break; | ||
| 357 | case PICA_REG_INDEX(tev_stage3.color_scale): | 237 | case PICA_REG_INDEX(tev_stage3.color_scale): |
| 358 | SyncTevMultipliers(3, regs.tev_stage3); | ||
| 359 | break; | ||
| 360 | |||
| 361 | // TEV stage 4 | ||
| 362 | case PICA_REG_INDEX(tev_stage4.color_source1): | 238 | case PICA_REG_INDEX(tev_stage4.color_source1): |
| 363 | SyncTevSources(4, regs.tev_stage4); | ||
| 364 | break; | ||
| 365 | case PICA_REG_INDEX(tev_stage4.color_modifier1): | 239 | case PICA_REG_INDEX(tev_stage4.color_modifier1): |
| 366 | SyncTevModifiers(4, regs.tev_stage4); | ||
| 367 | break; | ||
| 368 | case PICA_REG_INDEX(tev_stage4.color_op): | 240 | case PICA_REG_INDEX(tev_stage4.color_op): |
| 369 | SyncTevOps(4, regs.tev_stage4); | 241 | case PICA_REG_INDEX(tev_stage4.color_scale): |
| 242 | case PICA_REG_INDEX(tev_stage5.color_source1): | ||
| 243 | case PICA_REG_INDEX(tev_stage5.color_modifier1): | ||
| 244 | case PICA_REG_INDEX(tev_stage5.color_op): | ||
| 245 | case PICA_REG_INDEX(tev_stage5.color_scale): | ||
| 246 | case PICA_REG_INDEX(tev_combiner_buffer_input): | ||
| 247 | state.draw.shader_dirty = true; | ||
| 370 | break; | 248 | break; |
| 371 | case PICA_REG_INDEX(tev_stage4.const_r): | 249 | case PICA_REG_INDEX(tev_stage0.const_r): |
| 372 | SyncTevColor(4, regs.tev_stage4); | 250 | SyncTevConstColor(0, regs.tev_stage0); |
| 373 | break; | 251 | break; |
| 374 | case PICA_REG_INDEX(tev_stage4.color_scale): | 252 | case PICA_REG_INDEX(tev_stage1.const_r): |
| 375 | SyncTevMultipliers(4, regs.tev_stage4); | 253 | SyncTevConstColor(1, regs.tev_stage1); |
| 376 | break; | 254 | break; |
| 377 | 255 | case PICA_REG_INDEX(tev_stage2.const_r): | |
| 378 | // TEV stage 5 | 256 | SyncTevConstColor(2, regs.tev_stage2); |
| 379 | case PICA_REG_INDEX(tev_stage5.color_source1): | ||
| 380 | SyncTevSources(5, regs.tev_stage5); | ||
| 381 | break; | 257 | break; |
| 382 | case PICA_REG_INDEX(tev_stage5.color_modifier1): | 258 | case PICA_REG_INDEX(tev_stage3.const_r): |
| 383 | SyncTevModifiers(5, regs.tev_stage5); | 259 | SyncTevConstColor(3, regs.tev_stage3); |
| 384 | break; | 260 | break; |
| 385 | case PICA_REG_INDEX(tev_stage5.color_op): | 261 | case PICA_REG_INDEX(tev_stage4.const_r): |
| 386 | SyncTevOps(5, regs.tev_stage5); | 262 | SyncTevConstColor(4, regs.tev_stage4); |
| 387 | break; | 263 | break; |
| 388 | case PICA_REG_INDEX(tev_stage5.const_r): | 264 | case PICA_REG_INDEX(tev_stage5.const_r): |
| 389 | SyncTevColor(5, regs.tev_stage5); | 265 | SyncTevConstColor(5, regs.tev_stage5); |
| 390 | break; | ||
| 391 | case PICA_REG_INDEX(tev_stage5.color_scale): | ||
| 392 | SyncTevMultipliers(5, regs.tev_stage5); | ||
| 393 | break; | 266 | break; |
| 394 | 267 | ||
| 395 | // TEV combiner buffer color | 268 | // TEV combiner buffer color |
| 396 | case PICA_REG_INDEX(tev_combiner_buffer_color): | 269 | case PICA_REG_INDEX(tev_combiner_buffer_color): |
| 397 | SyncCombinerColor(); | 270 | SyncCombinerColor(); |
| 398 | break; | 271 | break; |
| 399 | |||
| 400 | // TEV combiner buffer write flags | ||
| 401 | case PICA_REG_INDEX(tev_combiner_buffer_input): | ||
| 402 | SyncCombinerWriteFlags(); | ||
| 403 | break; | ||
| 404 | } | 272 | } |
| 405 | } | 273 | } |
| 406 | 274 | ||
| @@ -592,6 +460,41 @@ void RasterizerOpenGL::ReconfigureDepthTexture(DepthTextureInfo& texture, Pica:: | |||
| 592 | state.Apply(); | 460 | state.Apply(); |
| 593 | } | 461 | } |
| 594 | 462 | ||
| 463 | void RasterizerOpenGL::SetShader() { | ||
| 464 | PicaShaderConfig config = PicaShaderConfig::CurrentConfig(); | ||
| 465 | std::unique_ptr<PicaShader> shader = Common::make_unique<PicaShader>(); | ||
| 466 | |||
| 467 | // Find (or generate) the GLSL shader for the current TEV state | ||
| 468 | auto cached_shader = shader_cache.find(config); | ||
| 469 | if (cached_shader != shader_cache.end()) { | ||
| 470 | current_shader = cached_shader->second.get(); | ||
| 471 | |||
| 472 | state.draw.shader_program = current_shader->shader.handle; | ||
| 473 | state.Apply(); | ||
| 474 | } else { | ||
| 475 | LOG_DEBUG(Render_OpenGL, "Creating new shader"); | ||
| 476 | |||
| 477 | shader->shader.Create(GLShader::GenerateVertexShader().c_str(), GLShader::GenerateFragmentShader(config).c_str()); | ||
| 478 | |||
| 479 | state.draw.shader_program = shader->shader.handle; | ||
| 480 | state.Apply(); | ||
| 481 | |||
| 482 | // Set the texture samplers to correspond to different texture units | ||
| 483 | glUniform1i(PicaShader::Uniform::Texture0, 0); | ||
| 484 | glUniform1i(PicaShader::Uniform::Texture1, 1); | ||
| 485 | glUniform1i(PicaShader::Uniform::Texture2, 2); | ||
| 486 | |||
| 487 | current_shader = shader_cache.emplace(config, std::move(shader)).first->second.get(); | ||
| 488 | } | ||
| 489 | |||
| 490 | // Update uniforms | ||
| 491 | SyncAlphaTest(); | ||
| 492 | SyncCombinerColor(); | ||
| 493 | auto& tev_stages = Pica::g_state.regs.GetTevStages(); | ||
| 494 | for (int index = 0; index < tev_stages.size(); ++index) | ||
| 495 | SyncTevConstColor(index, tev_stages[index]); | ||
| 496 | } | ||
| 497 | |||
| 595 | void RasterizerOpenGL::SyncFramebuffer() { | 498 | void RasterizerOpenGL::SyncFramebuffer() { |
| 596 | const auto& regs = Pica::g_state.regs; | 499 | const auto& regs = Pica::g_state.regs; |
| 597 | 500 | ||
| @@ -601,8 +504,8 @@ void RasterizerOpenGL::SyncFramebuffer() { | |||
| 601 | PAddr cur_fb_depth_addr = regs.framebuffer.GetDepthBufferPhysicalAddress(); | 504 | PAddr cur_fb_depth_addr = regs.framebuffer.GetDepthBufferPhysicalAddress(); |
| 602 | Pica::Regs::DepthFormat new_fb_depth_format = regs.framebuffer.depth_format; | 505 | Pica::Regs::DepthFormat new_fb_depth_format = regs.framebuffer.depth_format; |
| 603 | 506 | ||
| 604 | bool fb_size_changed = fb_color_texture.width != regs.framebuffer.GetWidth() || | 507 | bool fb_size_changed = fb_color_texture.width != static_cast<GLsizei>(regs.framebuffer.GetWidth()) || |
| 605 | fb_color_texture.height != regs.framebuffer.GetHeight(); | 508 | fb_color_texture.height != static_cast<GLsizei>(regs.framebuffer.GetHeight()); |
| 606 | 509 | ||
| 607 | bool color_fb_prop_changed = fb_color_texture.format != new_fb_color_format || | 510 | bool color_fb_prop_changed = fb_color_texture.format != new_fb_color_format || |
| 608 | fb_size_changed; | 511 | fb_size_changed; |
| @@ -712,9 +615,7 @@ void RasterizerOpenGL::SyncBlendColor() { | |||
| 712 | 615 | ||
| 713 | void RasterizerOpenGL::SyncAlphaTest() { | 616 | void RasterizerOpenGL::SyncAlphaTest() { |
| 714 | const auto& regs = Pica::g_state.regs; | 617 | const auto& regs = Pica::g_state.regs; |
| 715 | glUniform1i(uniform_alphatest_enabled, regs.output_merger.alpha_test.enable); | 618 | glUniform1i(PicaShader::Uniform::AlphaTestRef, regs.output_merger.alpha_test.ref); |
| 716 | glUniform1i(uniform_alphatest_func, (GLint)regs.output_merger.alpha_test.func.Value()); | ||
| 717 | glUniform1f(uniform_alphatest_ref, regs.output_merger.alpha_test.ref / 255.0f); | ||
| 718 | } | 619 | } |
| 719 | 620 | ||
| 720 | void RasterizerOpenGL::SyncLogicOp() { | 621 | void RasterizerOpenGL::SyncLogicOp() { |
| @@ -744,56 +645,14 @@ void RasterizerOpenGL::SyncDepthTest() { | |||
| 744 | state.depth.write_mask = regs.output_merger.depth_write_enable ? GL_TRUE : GL_FALSE; | 645 | state.depth.write_mask = regs.output_merger.depth_write_enable ? GL_TRUE : GL_FALSE; |
| 745 | } | 646 | } |
| 746 | 647 | ||
| 747 | void RasterizerOpenGL::SyncTevSources(unsigned stage_index, const Pica::Regs::TevStageConfig& config) { | ||
| 748 | GLint color_srcs[3] = { (GLint)config.color_source1.Value(), | ||
| 749 | (GLint)config.color_source2.Value(), | ||
| 750 | (GLint)config.color_source3.Value() }; | ||
| 751 | GLint alpha_srcs[3] = { (GLint)config.alpha_source1.Value(), | ||
| 752 | (GLint)config.alpha_source2.Value(), | ||
| 753 | (GLint)config.alpha_source3.Value() }; | ||
| 754 | |||
| 755 | glUniform3iv(uniform_tev_cfgs[stage_index].color_sources, 1, color_srcs); | ||
| 756 | glUniform3iv(uniform_tev_cfgs[stage_index].alpha_sources, 1, alpha_srcs); | ||
| 757 | } | ||
| 758 | |||
| 759 | void RasterizerOpenGL::SyncTevModifiers(unsigned stage_index, const Pica::Regs::TevStageConfig& config) { | ||
| 760 | GLint color_mods[3] = { (GLint)config.color_modifier1.Value(), | ||
| 761 | (GLint)config.color_modifier2.Value(), | ||
| 762 | (GLint)config.color_modifier3.Value() }; | ||
| 763 | GLint alpha_mods[3] = { (GLint)config.alpha_modifier1.Value(), | ||
| 764 | (GLint)config.alpha_modifier2.Value(), | ||
| 765 | (GLint)config.alpha_modifier3.Value() }; | ||
| 766 | |||
| 767 | glUniform3iv(uniform_tev_cfgs[stage_index].color_modifiers, 1, color_mods); | ||
| 768 | glUniform3iv(uniform_tev_cfgs[stage_index].alpha_modifiers, 1, alpha_mods); | ||
| 769 | } | ||
| 770 | |||
| 771 | void RasterizerOpenGL::SyncTevOps(unsigned stage_index, const Pica::Regs::TevStageConfig& config) { | ||
| 772 | glUniform2i(uniform_tev_cfgs[stage_index].color_alpha_op, (GLint)config.color_op.Value(), (GLint)config.alpha_op.Value()); | ||
| 773 | } | ||
| 774 | |||
| 775 | void RasterizerOpenGL::SyncTevColor(unsigned stage_index, const Pica::Regs::TevStageConfig& config) { | ||
| 776 | auto const_color = PicaToGL::ColorRGBA8(config.const_color); | ||
| 777 | glUniform4fv(uniform_tev_cfgs[stage_index].const_color, 1, const_color.data()); | ||
| 778 | } | ||
| 779 | |||
| 780 | void RasterizerOpenGL::SyncTevMultipliers(unsigned stage_index, const Pica::Regs::TevStageConfig& config) { | ||
| 781 | glUniform2i(uniform_tev_cfgs[stage_index].color_alpha_multiplier, config.GetColorMultiplier(), config.GetAlphaMultiplier()); | ||
| 782 | } | ||
| 783 | |||
| 784 | void RasterizerOpenGL::SyncCombinerColor() { | 648 | void RasterizerOpenGL::SyncCombinerColor() { |
| 785 | auto combiner_color = PicaToGL::ColorRGBA8(Pica::g_state.regs.tev_combiner_buffer_color.raw); | 649 | auto combiner_color = PicaToGL::ColorRGBA8(Pica::g_state.regs.tev_combiner_buffer_color.raw); |
| 786 | glUniform4fv(uniform_tev_combiner_buffer_color, 1, combiner_color.data()); | 650 | glUniform4fv(PicaShader::Uniform::TevCombinerBufferColor, 1, combiner_color.data()); |
| 787 | } | 651 | } |
| 788 | 652 | ||
| 789 | void RasterizerOpenGL::SyncCombinerWriteFlags() { | 653 | void RasterizerOpenGL::SyncTevConstColor(int stage_index, const Pica::Regs::TevStageConfig& tev_stage) { |
| 790 | const auto& regs = Pica::g_state.regs; | 654 | auto const_color = PicaToGL::ColorRGBA8(tev_stage.const_color); |
| 791 | const auto tev_stages = regs.GetTevStages(); | 655 | glUniform4fv(PicaShader::Uniform::TevConstColors + stage_index, 1, const_color.data()); |
| 792 | for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size(); ++tev_stage_index) { | ||
| 793 | glUniform2i(uniform_tev_cfgs[tev_stage_index].updates_combiner_buffer_color_alpha, | ||
| 794 | regs.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferColor(tev_stage_index), | ||
| 795 | regs.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferAlpha(tev_stage_index)); | ||
| 796 | } | ||
| 797 | } | 656 | } |
| 798 | 657 | ||
| 799 | void RasterizerOpenGL::SyncDrawState() { | 658 | void RasterizerOpenGL::SyncDrawState() { |
| @@ -824,12 +683,6 @@ void RasterizerOpenGL::SyncDrawState() { | |||
| 824 | } | 683 | } |
| 825 | } | 684 | } |
| 826 | 685 | ||
| 827 | // Skip processing TEV stages that simply pass the previous stage results through | ||
| 828 | const auto tev_stages = regs.GetTevStages(); | ||
| 829 | for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size(); ++tev_stage_index) { | ||
| 830 | glUniform1i(uniform_tev_cfgs[tev_stage_index].enabled, !IsPassThroughTevStage(tev_stages[tev_stage_index])); | ||
| 831 | } | ||
| 832 | |||
| 833 | state.Apply(); | 686 | state.Apply(); |
| 834 | } | 687 | } |
| 835 | 688 | ||
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 1fe307846..872cae7da 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h | |||
| @@ -4,15 +4,104 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <cstddef> | ||
| 8 | #include <cstring> | ||
| 9 | #include <memory> | ||
| 7 | #include <vector> | 10 | #include <vector> |
| 11 | #include <unordered_map> | ||
| 8 | 12 | ||
| 9 | #include "common/common_types.h" | 13 | #include "common/common_types.h" |
| 14 | #include "common/hash.h" | ||
| 10 | 15 | ||
| 16 | #include "video_core/pica.h" | ||
| 11 | #include "video_core/hwrasterizer_base.h" | 17 | #include "video_core/hwrasterizer_base.h" |
| 12 | #include "video_core/renderer_opengl/gl_rasterizer_cache.h" | 18 | #include "video_core/renderer_opengl/gl_rasterizer_cache.h" |
| 13 | #include "video_core/renderer_opengl/gl_state.h" | 19 | #include "video_core/renderer_opengl/gl_state.h" |
| 14 | #include "video_core/shader/shader_interpreter.h" | 20 | #include "video_core/shader/shader_interpreter.h" |
| 15 | 21 | ||
| 22 | /** | ||
| 23 | * This struct contains all state used to generate the GLSL shader program that emulates the current | ||
| 24 | * Pica register configuration. This struct is used as a cache key for generated GLSL shader | ||
| 25 | * programs. The functions in gl_shader_gen.cpp should retrieve state from this struct only, not by | ||
| 26 | * directly accessing Pica registers. This should reduce the risk of bugs in shader generation where | ||
| 27 | * Pica state is not being captured in the shader cache key, thereby resulting in (what should be) | ||
| 28 | * two separate shaders sharing the same key. | ||
| 29 | */ | ||
| 30 | struct PicaShaderConfig { | ||
| 31 | /// Construct a PicaShaderConfig with the current Pica register configuration. | ||
| 32 | static PicaShaderConfig CurrentConfig() { | ||
| 33 | PicaShaderConfig res; | ||
| 34 | const auto& regs = Pica::g_state.regs; | ||
| 35 | |||
| 36 | res.alpha_test_func = regs.output_merger.alpha_test.enable ? | ||
| 37 | regs.output_merger.alpha_test.func.Value() : Pica::Regs::CompareFunc::Always; | ||
| 38 | |||
| 39 | // Copy relevant TevStageConfig fields only. We're doing this manually (instead of calling | ||
| 40 | // the GetTevStages() function) because BitField explicitly disables copies. | ||
| 41 | |||
| 42 | res.tev_stages[0].sources_raw = regs.tev_stage0.sources_raw; | ||
| 43 | res.tev_stages[1].sources_raw = regs.tev_stage1.sources_raw; | ||
| 44 | res.tev_stages[2].sources_raw = regs.tev_stage2.sources_raw; | ||
| 45 | res.tev_stages[3].sources_raw = regs.tev_stage3.sources_raw; | ||
| 46 | res.tev_stages[4].sources_raw = regs.tev_stage4.sources_raw; | ||
| 47 | res.tev_stages[5].sources_raw = regs.tev_stage5.sources_raw; | ||
| 48 | |||
| 49 | res.tev_stages[0].modifiers_raw = regs.tev_stage0.modifiers_raw; | ||
| 50 | res.tev_stages[1].modifiers_raw = regs.tev_stage1.modifiers_raw; | ||
| 51 | res.tev_stages[2].modifiers_raw = regs.tev_stage2.modifiers_raw; | ||
| 52 | res.tev_stages[3].modifiers_raw = regs.tev_stage3.modifiers_raw; | ||
| 53 | res.tev_stages[4].modifiers_raw = regs.tev_stage4.modifiers_raw; | ||
| 54 | res.tev_stages[5].modifiers_raw = regs.tev_stage5.modifiers_raw; | ||
| 55 | |||
| 56 | res.tev_stages[0].ops_raw = regs.tev_stage0.ops_raw; | ||
| 57 | res.tev_stages[1].ops_raw = regs.tev_stage1.ops_raw; | ||
| 58 | res.tev_stages[2].ops_raw = regs.tev_stage2.ops_raw; | ||
| 59 | res.tev_stages[3].ops_raw = regs.tev_stage3.ops_raw; | ||
| 60 | res.tev_stages[4].ops_raw = regs.tev_stage4.ops_raw; | ||
| 61 | res.tev_stages[5].ops_raw = regs.tev_stage5.ops_raw; | ||
| 62 | |||
| 63 | res.tev_stages[0].scales_raw = regs.tev_stage0.scales_raw; | ||
| 64 | res.tev_stages[1].scales_raw = regs.tev_stage1.scales_raw; | ||
| 65 | res.tev_stages[2].scales_raw = regs.tev_stage2.scales_raw; | ||
| 66 | res.tev_stages[3].scales_raw = regs.tev_stage3.scales_raw; | ||
| 67 | res.tev_stages[4].scales_raw = regs.tev_stage4.scales_raw; | ||
| 68 | res.tev_stages[5].scales_raw = regs.tev_stage5.scales_raw; | ||
| 69 | |||
| 70 | res.combiner_buffer_input = | ||
| 71 | regs.tev_combiner_buffer_input.update_mask_rgb.Value() | | ||
| 72 | regs.tev_combiner_buffer_input.update_mask_a.Value() << 4; | ||
| 73 | |||
| 74 | return res; | ||
| 75 | } | ||
| 76 | |||
| 77 | bool TevStageUpdatesCombinerBufferColor(unsigned stage_index) const { | ||
| 78 | return (stage_index < 4) && (combiner_buffer_input & (1 << stage_index)); | ||
| 79 | } | ||
| 80 | |||
| 81 | bool TevStageUpdatesCombinerBufferAlpha(unsigned stage_index) const { | ||
| 82 | return (stage_index < 4) && ((combiner_buffer_input >> 4) & (1 << stage_index)); | ||
| 83 | } | ||
| 84 | |||
| 85 | bool operator ==(const PicaShaderConfig& o) const { | ||
| 86 | return std::memcmp(this, &o, sizeof(PicaShaderConfig)) == 0; | ||
| 87 | }; | ||
| 88 | |||
| 89 | Pica::Regs::CompareFunc alpha_test_func; | ||
| 90 | std::array<Pica::Regs::TevStageConfig, 6> tev_stages = {}; | ||
| 91 | u8 combiner_buffer_input; | ||
| 92 | }; | ||
| 93 | |||
| 94 | namespace std { | ||
| 95 | |||
| 96 | template <> | ||
| 97 | struct hash<PicaShaderConfig> { | ||
| 98 | size_t operator()(const PicaShaderConfig& k) const { | ||
| 99 | return Common::ComputeHash64(&k, sizeof(PicaShaderConfig)); | ||
| 100 | } | ||
| 101 | }; | ||
| 102 | |||
| 103 | } // namespace std | ||
| 104 | |||
| 16 | class RasterizerOpenGL : public HWRasterizer { | 105 | class RasterizerOpenGL : public HWRasterizer { |
| 17 | public: | 106 | public: |
| 18 | 107 | ||
| @@ -45,20 +134,24 @@ public: | |||
| 45 | /// Notify rasterizer that a 3DS memory region has been changed | 134 | /// Notify rasterizer that a 3DS memory region has been changed |
| 46 | void NotifyFlush(PAddr addr, u32 size) override; | 135 | void NotifyFlush(PAddr addr, u32 size) override; |
| 47 | 136 | ||
| 48 | private: | 137 | /// OpenGL shader generated for a given Pica register state |
| 49 | /// Structure used for managing texture environment states | 138 | struct PicaShader { |
| 50 | struct TEVConfigUniforms { | 139 | /// OpenGL shader resource |
| 51 | GLuint enabled; | 140 | OGLShader shader; |
| 52 | GLuint color_sources; | 141 | |
| 53 | GLuint alpha_sources; | 142 | /// Fragment shader uniforms |
| 54 | GLuint color_modifiers; | 143 | enum Uniform : GLuint { |
| 55 | GLuint alpha_modifiers; | 144 | AlphaTestRef = 0, |
| 56 | GLuint color_alpha_op; | 145 | TevConstColors = 1, |
| 57 | GLuint color_alpha_multiplier; | 146 | Texture0 = 7, |
| 58 | GLuint const_color; | 147 | Texture1 = 8, |
| 59 | GLuint updates_combiner_buffer_color_alpha; | 148 | Texture2 = 9, |
| 149 | TevCombinerBufferColor = 10, | ||
| 150 | }; | ||
| 60 | }; | 151 | }; |
| 61 | 152 | ||
| 153 | private: | ||
| 154 | |||
| 62 | /// Structure used for storing information about color textures | 155 | /// Structure used for storing information about color textures |
| 63 | struct TextureInfo { | 156 | struct TextureInfo { |
| 64 | OGLTexture texture; | 157 | OGLTexture texture; |
| @@ -129,6 +222,9 @@ private: | |||
| 129 | /// Reconfigure the OpenGL depth texture to use the given format and dimensions | 222 | /// Reconfigure the OpenGL depth texture to use the given format and dimensions |
| 130 | void ReconfigureDepthTexture(DepthTextureInfo& texture, Pica::Regs::DepthFormat format, u32 width, u32 height); | 223 | void ReconfigureDepthTexture(DepthTextureInfo& texture, Pica::Regs::DepthFormat format, u32 width, u32 height); |
| 131 | 224 | ||
| 225 | /// Sets the OpenGL shader in accordance with the current PICA register state | ||
| 226 | void SetShader(); | ||
| 227 | |||
| 132 | /// Syncs the state and contents of the OpenGL framebuffer to match the current PICA framebuffer | 228 | /// Syncs the state and contents of the OpenGL framebuffer to match the current PICA framebuffer |
| 133 | void SyncFramebuffer(); | 229 | void SyncFramebuffer(); |
| 134 | 230 | ||
| @@ -156,27 +252,12 @@ private: | |||
| 156 | /// Syncs the depth test states to match the PICA register | 252 | /// Syncs the depth test states to match the PICA register |
| 157 | void SyncDepthTest(); | 253 | void SyncDepthTest(); |
| 158 | 254 | ||
| 159 | /// Syncs the specified TEV stage's color and alpha sources to match the PICA register | 255 | /// Syncs the TEV constant color to match the PICA register |
| 160 | void SyncTevSources(unsigned stage_index, const Pica::Regs::TevStageConfig& config); | 256 | void SyncTevConstColor(int tev_index, const Pica::Regs::TevStageConfig& tev_stage); |
| 161 | |||
| 162 | /// Syncs the specified TEV stage's color and alpha modifiers to match the PICA register | ||
| 163 | void SyncTevModifiers(unsigned stage_index, const Pica::Regs::TevStageConfig& config); | ||
| 164 | |||
| 165 | /// Syncs the specified TEV stage's color and alpha combiner operations to match the PICA register | ||
| 166 | void SyncTevOps(unsigned stage_index, const Pica::Regs::TevStageConfig& config); | ||
| 167 | |||
| 168 | /// Syncs the specified TEV stage's constant color to match the PICA register | ||
| 169 | void SyncTevColor(unsigned stage_index, const Pica::Regs::TevStageConfig& config); | ||
| 170 | |||
| 171 | /// Syncs the specified TEV stage's color and alpha multipliers to match the PICA register | ||
| 172 | void SyncTevMultipliers(unsigned stage_index, const Pica::Regs::TevStageConfig& config); | ||
| 173 | 257 | ||
| 174 | /// Syncs the TEV combiner color buffer to match the PICA register | 258 | /// Syncs the TEV combiner color buffer to match the PICA register |
| 175 | void SyncCombinerColor(); | 259 | void SyncCombinerColor(); |
| 176 | 260 | ||
| 177 | /// Syncs the TEV combiner write flags to match the PICA register | ||
| 178 | void SyncCombinerWriteFlags(); | ||
| 179 | |||
| 180 | /// Syncs the remaining OpenGL drawing state to match the current PICA state | 261 | /// Syncs the remaining OpenGL drawing state to match the current PICA state |
| 181 | void SyncDrawState(); | 262 | void SyncDrawState(); |
| 182 | 263 | ||
| @@ -213,21 +294,11 @@ private: | |||
| 213 | std::array<SamplerInfo, 3> texture_samplers; | 294 | std::array<SamplerInfo, 3> texture_samplers; |
| 214 | TextureInfo fb_color_texture; | 295 | TextureInfo fb_color_texture; |
| 215 | DepthTextureInfo fb_depth_texture; | 296 | DepthTextureInfo fb_depth_texture; |
| 216 | OGLShader shader; | 297 | |
| 298 | std::unordered_map<PicaShaderConfig, std::unique_ptr<PicaShader>> shader_cache; | ||
| 299 | const PicaShader* current_shader = nullptr; | ||
| 300 | |||
| 217 | OGLVertexArray vertex_array; | 301 | OGLVertexArray vertex_array; |
| 218 | OGLBuffer vertex_buffer; | 302 | OGLBuffer vertex_buffer; |
| 219 | OGLFramebuffer framebuffer; | 303 | OGLFramebuffer framebuffer; |
| 220 | |||
| 221 | // Hardware vertex shader | ||
| 222 | GLuint attrib_position; | ||
| 223 | GLuint attrib_color; | ||
| 224 | GLuint attrib_texcoords; | ||
| 225 | |||
| 226 | // Hardware fragment shader | ||
| 227 | GLuint uniform_alphatest_enabled; | ||
| 228 | GLuint uniform_alphatest_func; | ||
| 229 | GLuint uniform_alphatest_ref; | ||
| 230 | GLuint uniform_tex; | ||
| 231 | GLuint uniform_tev_combiner_buffer_color; | ||
| 232 | TEVConfigUniforms uniform_tev_cfgs[6]; | ||
| 233 | }; | 304 | }; |
diff --git a/src/video_core/renderer_opengl/gl_resource_manager.h b/src/video_core/renderer_opengl/gl_resource_manager.h index 65034d40d..eb128966c 100644 --- a/src/video_core/renderer_opengl/gl_resource_manager.h +++ b/src/video_core/renderer_opengl/gl_resource_manager.h | |||
| @@ -71,7 +71,7 @@ public: | |||
| 71 | /// Creates a new internal OpenGL resource and stores the handle | 71 | /// Creates a new internal OpenGL resource and stores the handle |
| 72 | void Create(const char* vert_shader, const char* frag_shader) { | 72 | void Create(const char* vert_shader, const char* frag_shader) { |
| 73 | if (handle != 0) return; | 73 | if (handle != 0) return; |
| 74 | handle = ShaderUtil::LoadShaders(vert_shader, frag_shader); | 74 | handle = GLShader::LoadProgram(vert_shader, frag_shader); |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | /// Deletes the internal OpenGL resource | 77 | /// Deletes the internal OpenGL resource |
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp new file mode 100644 index 000000000..d19d15e75 --- /dev/null +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp | |||
| @@ -0,0 +1,388 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "video_core/pica.h" | ||
| 6 | #include "video_core/renderer_opengl/gl_rasterizer.h" | ||
| 7 | #include "video_core/renderer_opengl/gl_shader_gen.h" | ||
| 8 | |||
| 9 | using Pica::Regs; | ||
| 10 | using TevStageConfig = Regs::TevStageConfig; | ||
| 11 | |||
| 12 | namespace GLShader { | ||
| 13 | |||
| 14 | /// Detects if a TEV stage is configured to be skipped (to avoid generating unnecessary code) | ||
| 15 | static bool IsPassThroughTevStage(const TevStageConfig& stage) { | ||
| 16 | return (stage.color_op == TevStageConfig::Operation::Replace && | ||
| 17 | stage.alpha_op == TevStageConfig::Operation::Replace && | ||
| 18 | stage.color_source1 == TevStageConfig::Source::Previous && | ||
| 19 | stage.alpha_source1 == TevStageConfig::Source::Previous && | ||
| 20 | stage.color_modifier1 == TevStageConfig::ColorModifier::SourceColor && | ||
| 21 | stage.alpha_modifier1 == TevStageConfig::AlphaModifier::SourceAlpha && | ||
| 22 | stage.GetColorMultiplier() == 1 && | ||
| 23 | stage.GetAlphaMultiplier() == 1); | ||
| 24 | } | ||
| 25 | |||
| 26 | /// Writes the specified TEV stage source component(s) | ||
| 27 | static void AppendSource(std::string& out, TevStageConfig::Source source, | ||
| 28 | const std::string& index_name) { | ||
| 29 | using Source = TevStageConfig::Source; | ||
| 30 | switch (source) { | ||
| 31 | case Source::PrimaryColor: | ||
| 32 | out += "primary_color"; | ||
| 33 | break; | ||
| 34 | case Source::PrimaryFragmentColor: | ||
| 35 | // HACK: Until we implement fragment lighting, use primary_color | ||
| 36 | out += "primary_color"; | ||
| 37 | break; | ||
| 38 | case Source::SecondaryFragmentColor: | ||
| 39 | // HACK: Until we implement fragment lighting, use zero | ||
| 40 | out += "vec4(0.0)"; | ||
| 41 | break; | ||
| 42 | case Source::Texture0: | ||
| 43 | out += "texture(tex[0], texcoord[0])"; | ||
| 44 | break; | ||
| 45 | case Source::Texture1: | ||
| 46 | out += "texture(tex[1], texcoord[1])"; | ||
| 47 | break; | ||
| 48 | case Source::Texture2: | ||
| 49 | out += "texture(tex[2], texcoord[2])"; | ||
| 50 | break; | ||
| 51 | case Source::PreviousBuffer: | ||
| 52 | out += "combiner_buffer"; | ||
| 53 | break; | ||
| 54 | case Source::Constant: | ||
| 55 | ((out += "const_color[") += index_name) += ']'; | ||
| 56 | break; | ||
| 57 | case Source::Previous: | ||
| 58 | out += "last_tex_env_out"; | ||
| 59 | break; | ||
| 60 | default: | ||
| 61 | out += "vec4(0.0)"; | ||
| 62 | LOG_CRITICAL(Render_OpenGL, "Unknown source op %u", source); | ||
| 63 | break; | ||
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 67 | /// Writes the color components to use for the specified TEV stage color modifier | ||
| 68 | static void AppendColorModifier(std::string& out, TevStageConfig::ColorModifier modifier, | ||
| 69 | TevStageConfig::Source source, const std::string& index_name) { | ||
| 70 | using ColorModifier = TevStageConfig::ColorModifier; | ||
| 71 | switch (modifier) { | ||
| 72 | case ColorModifier::SourceColor: | ||
| 73 | AppendSource(out, source, index_name); | ||
| 74 | out += ".rgb"; | ||
| 75 | break; | ||
| 76 | case ColorModifier::OneMinusSourceColor: | ||
| 77 | out += "vec3(1.0) - "; | ||
| 78 | AppendSource(out, source, index_name); | ||
| 79 | out += ".rgb"; | ||
| 80 | break; | ||
| 81 | case ColorModifier::SourceAlpha: | ||
| 82 | AppendSource(out, source, index_name); | ||
| 83 | out += ".aaa"; | ||
| 84 | break; | ||
| 85 | case ColorModifier::OneMinusSourceAlpha: | ||
| 86 | out += "vec3(1.0) - "; | ||
| 87 | AppendSource(out, source, index_name); | ||
| 88 | out += ".aaa"; | ||
| 89 | break; | ||
| 90 | case ColorModifier::SourceRed: | ||
| 91 | AppendSource(out, source, index_name); | ||
| 92 | out += ".rrr"; | ||
| 93 | break; | ||
| 94 | case ColorModifier::OneMinusSourceRed: | ||
| 95 | out += "vec3(1.0) - "; | ||
| 96 | AppendSource(out, source, index_name); | ||
| 97 | out += ".rrr"; | ||
| 98 | break; | ||
| 99 | case ColorModifier::SourceGreen: | ||
| 100 | AppendSource(out, source, index_name); | ||
| 101 | out += ".ggg"; | ||
| 102 | break; | ||
| 103 | case ColorModifier::OneMinusSourceGreen: | ||
| 104 | out += "vec3(1.0) - "; | ||
| 105 | AppendSource(out, source, index_name); | ||
| 106 | out += ".ggg"; | ||
| 107 | break; | ||
| 108 | case ColorModifier::SourceBlue: | ||
| 109 | AppendSource(out, source, index_name); | ||
| 110 | out += ".bbb"; | ||
| 111 | break; | ||
| 112 | case ColorModifier::OneMinusSourceBlue: | ||
| 113 | out += "vec3(1.0) - "; | ||
| 114 | AppendSource(out, source, index_name); | ||
| 115 | out += ".bbb"; | ||
| 116 | break; | ||
| 117 | default: | ||
| 118 | out += "vec3(0.0)"; | ||
| 119 | LOG_CRITICAL(Render_OpenGL, "Unknown color modifier op %u", modifier); | ||
| 120 | break; | ||
| 121 | } | ||
| 122 | } | ||
| 123 | |||
| 124 | /// Writes the alpha component to use for the specified TEV stage alpha modifier | ||
| 125 | static void AppendAlphaModifier(std::string& out, TevStageConfig::AlphaModifier modifier, | ||
| 126 | TevStageConfig::Source source, const std::string& index_name) { | ||
| 127 | using AlphaModifier = TevStageConfig::AlphaModifier; | ||
| 128 | switch (modifier) { | ||
| 129 | case AlphaModifier::SourceAlpha: | ||
| 130 | AppendSource(out, source, index_name); | ||
| 131 | out += ".a"; | ||
| 132 | break; | ||
| 133 | case AlphaModifier::OneMinusSourceAlpha: | ||
| 134 | out += "1.0 - "; | ||
| 135 | AppendSource(out, source, index_name); | ||
| 136 | out += ".a"; | ||
| 137 | break; | ||
| 138 | case AlphaModifier::SourceRed: | ||
| 139 | AppendSource(out, source, index_name); | ||
| 140 | out += ".r"; | ||
| 141 | break; | ||
| 142 | case AlphaModifier::OneMinusSourceRed: | ||
| 143 | out += "1.0 - "; | ||
| 144 | AppendSource(out, source, index_name); | ||
| 145 | out += ".r"; | ||
| 146 | break; | ||
| 147 | case AlphaModifier::SourceGreen: | ||
| 148 | AppendSource(out, source, index_name); | ||
| 149 | out += ".g"; | ||
| 150 | break; | ||
| 151 | case AlphaModifier::OneMinusSourceGreen: | ||
| 152 | out += "1.0 - "; | ||
| 153 | AppendSource(out, source, index_name); | ||
| 154 | out += ".g"; | ||
| 155 | break; | ||
| 156 | case AlphaModifier::SourceBlue: | ||
| 157 | AppendSource(out, source, index_name); | ||
| 158 | out += ".b"; | ||
| 159 | break; | ||
| 160 | case AlphaModifier::OneMinusSourceBlue: | ||
| 161 | out += "1.0 - "; | ||
| 162 | AppendSource(out, source, index_name); | ||
| 163 | out += ".b"; | ||
| 164 | break; | ||
| 165 | default: | ||
| 166 | out += "0.0"; | ||
| 167 | LOG_CRITICAL(Render_OpenGL, "Unknown alpha modifier op %u", modifier); | ||
| 168 | break; | ||
| 169 | } | ||
| 170 | } | ||
| 171 | |||
| 172 | /// Writes the combiner function for the color components for the specified TEV stage operation | ||
| 173 | static void AppendColorCombiner(std::string& out, TevStageConfig::Operation operation, | ||
| 174 | const std::string& variable_name) { | ||
| 175 | out += "clamp("; | ||
| 176 | using Operation = TevStageConfig::Operation; | ||
| 177 | switch (operation) { | ||
| 178 | case Operation::Replace: | ||
| 179 | out += variable_name + "[0]"; | ||
| 180 | break; | ||
| 181 | case Operation::Modulate: | ||
| 182 | out += variable_name + "[0] * " + variable_name + "[1]"; | ||
| 183 | break; | ||
| 184 | case Operation::Add: | ||
| 185 | out += variable_name + "[0] + " + variable_name + "[1]"; | ||
| 186 | break; | ||
| 187 | case Operation::AddSigned: | ||
| 188 | out += variable_name + "[0] + " + variable_name + "[1] - vec3(0.5)"; | ||
| 189 | break; | ||
| 190 | case Operation::Lerp: | ||
| 191 | // TODO(bunnei): Verify if HW actually does this per-component, otherwise we can just use builtin lerp | ||
| 192 | out += variable_name + "[0] * " + variable_name + "[2] + " + variable_name + "[1] * (vec3(1.0) - " + variable_name + "[2])"; | ||
| 193 | break; | ||
| 194 | case Operation::Subtract: | ||
| 195 | out += variable_name + "[0] - " + variable_name + "[1]"; | ||
| 196 | break; | ||
| 197 | case Operation::MultiplyThenAdd: | ||
| 198 | out += variable_name + "[0] * " + variable_name + "[1] + " + variable_name + "[2]"; | ||
| 199 | break; | ||
| 200 | case Operation::AddThenMultiply: | ||
| 201 | out += "min(" + variable_name + "[0] + " + variable_name + "[1], vec3(1.0)) * " + variable_name + "[2]"; | ||
| 202 | break; | ||
| 203 | default: | ||
| 204 | out += "vec3(0.0)"; | ||
| 205 | LOG_CRITICAL(Render_OpenGL, "Unknown color combiner operation: %u", operation); | ||
| 206 | break; | ||
| 207 | } | ||
| 208 | out += ", vec3(0.0), vec3(1.0))"; // Clamp result to 0.0, 1.0 | ||
| 209 | } | ||
| 210 | |||
| 211 | /// Writes the combiner function for the alpha component for the specified TEV stage operation | ||
| 212 | static void AppendAlphaCombiner(std::string& out, TevStageConfig::Operation operation, | ||
| 213 | const std::string& variable_name) { | ||
| 214 | out += "clamp("; | ||
| 215 | using Operation = TevStageConfig::Operation; | ||
| 216 | switch (operation) { | ||
| 217 | case Operation::Replace: | ||
| 218 | out += variable_name + "[0]"; | ||
| 219 | break; | ||
| 220 | case Operation::Modulate: | ||
| 221 | out += variable_name + "[0] * " + variable_name + "[1]"; | ||
| 222 | break; | ||
| 223 | case Operation::Add: | ||
| 224 | out += variable_name + "[0] + " + variable_name + "[1]"; | ||
| 225 | break; | ||
| 226 | case Operation::AddSigned: | ||
| 227 | out += variable_name + "[0] + " + variable_name + "[1] - 0.5"; | ||
| 228 | break; | ||
| 229 | case Operation::Lerp: | ||
| 230 | out += variable_name + "[0] * " + variable_name + "[2] + " + variable_name + "[1] * (1.0 - " + variable_name + "[2])"; | ||
| 231 | break; | ||
| 232 | case Operation::Subtract: | ||
| 233 | out += variable_name + "[0] - " + variable_name + "[1]"; | ||
| 234 | break; | ||
| 235 | case Operation::MultiplyThenAdd: | ||
| 236 | out += variable_name + "[0] * " + variable_name + "[1] + " + variable_name + "[2]"; | ||
| 237 | break; | ||
| 238 | case Operation::AddThenMultiply: | ||
| 239 | out += "min(" + variable_name + "[0] + " + variable_name + "[1], 1.0) * " + variable_name + "[2]"; | ||
| 240 | break; | ||
| 241 | default: | ||
| 242 | out += "0.0"; | ||
| 243 | LOG_CRITICAL(Render_OpenGL, "Unknown alpha combiner operation: %u", operation); | ||
| 244 | break; | ||
| 245 | } | ||
| 246 | out += ", 0.0, 1.0)"; | ||
| 247 | } | ||
| 248 | |||
| 249 | /// Writes the if-statement condition used to evaluate alpha testing | ||
| 250 | static void AppendAlphaTestCondition(std::string& out, Regs::CompareFunc func) { | ||
| 251 | using CompareFunc = Regs::CompareFunc; | ||
| 252 | switch (func) { | ||
| 253 | case CompareFunc::Never: | ||
| 254 | out += "true"; | ||
| 255 | break; | ||
| 256 | case CompareFunc::Always: | ||
| 257 | out += "false"; | ||
| 258 | break; | ||
| 259 | case CompareFunc::Equal: | ||
| 260 | case CompareFunc::NotEqual: | ||
| 261 | case CompareFunc::LessThan: | ||
| 262 | case CompareFunc::LessThanOrEqual: | ||
| 263 | case CompareFunc::GreaterThan: | ||
| 264 | case CompareFunc::GreaterThanOrEqual: | ||
| 265 | { | ||
| 266 | static const char* op[] = { "!=", "==", ">=", ">", "<=", "<", }; | ||
| 267 | unsigned index = (unsigned)func - (unsigned)CompareFunc::Equal; | ||
| 268 | out += "int(last_tex_env_out.a * 255.0f) " + std::string(op[index]) + " alphatest_ref"; | ||
| 269 | break; | ||
| 270 | } | ||
| 271 | |||
| 272 | default: | ||
| 273 | out += "false"; | ||
| 274 | LOG_CRITICAL(Render_OpenGL, "Unknown alpha test condition %u", func); | ||
| 275 | break; | ||
| 276 | } | ||
| 277 | } | ||
| 278 | |||
| 279 | /// Writes the code to emulate the specified TEV stage | ||
| 280 | static void WriteTevStage(std::string& out, const PicaShaderConfig& config, unsigned index) { | ||
| 281 | auto& stage = config.tev_stages[index]; | ||
| 282 | if (!IsPassThroughTevStage(stage)) { | ||
| 283 | std::string index_name = std::to_string(index); | ||
| 284 | |||
| 285 | out += "vec3 color_results_" + index_name + "[3] = vec3[3]("; | ||
| 286 | AppendColorModifier(out, stage.color_modifier1, stage.color_source1, index_name); | ||
| 287 | out += ", "; | ||
| 288 | AppendColorModifier(out, stage.color_modifier2, stage.color_source2, index_name); | ||
| 289 | out += ", "; | ||
| 290 | AppendColorModifier(out, stage.color_modifier3, stage.color_source3, index_name); | ||
| 291 | out += ");\n"; | ||
| 292 | |||
| 293 | out += "vec3 color_output_" + index_name + " = "; | ||
| 294 | AppendColorCombiner(out, stage.color_op, "color_results_" + index_name); | ||
| 295 | out += ";\n"; | ||
| 296 | |||
| 297 | out += "float alpha_results_" + index_name + "[3] = float[3]("; | ||
| 298 | AppendAlphaModifier(out, stage.alpha_modifier1, stage.alpha_source1, index_name); | ||
| 299 | out += ", "; | ||
| 300 | AppendAlphaModifier(out, stage.alpha_modifier2, stage.alpha_source2, index_name); | ||
| 301 | out += ", "; | ||
| 302 | AppendAlphaModifier(out, stage.alpha_modifier3, stage.alpha_source3, index_name); | ||
| 303 | out += ");\n"; | ||
| 304 | |||
| 305 | out += "float alpha_output_" + index_name + " = "; | ||
| 306 | AppendAlphaCombiner(out, stage.alpha_op, "alpha_results_" + index_name); | ||
| 307 | out += ";\n"; | ||
| 308 | |||
| 309 | out += "last_tex_env_out = vec4(" | ||
| 310 | "clamp(color_output_" + index_name + " * " + std::to_string(stage.GetColorMultiplier()) + ".0, vec3(0.0), vec3(1.0))," | ||
| 311 | "clamp(alpha_output_" + index_name + " * " + std::to_string(stage.GetAlphaMultiplier()) + ".0, 0.0, 1.0));\n"; | ||
| 312 | } | ||
| 313 | |||
| 314 | if (config.TevStageUpdatesCombinerBufferColor(index)) | ||
| 315 | out += "combiner_buffer.rgb = last_tex_env_out.rgb;\n"; | ||
| 316 | |||
| 317 | if (config.TevStageUpdatesCombinerBufferAlpha(index)) | ||
| 318 | out += "combiner_buffer.a = last_tex_env_out.a;\n"; | ||
| 319 | } | ||
| 320 | |||
| 321 | std::string GenerateFragmentShader(const PicaShaderConfig& config) { | ||
| 322 | std::string out = R"( | ||
| 323 | #version 330 | ||
| 324 | #extension GL_ARB_explicit_uniform_location : require | ||
| 325 | |||
| 326 | #define NUM_TEV_STAGES 6 | ||
| 327 | |||
| 328 | in vec4 primary_color; | ||
| 329 | in vec2 texcoord[3]; | ||
| 330 | |||
| 331 | out vec4 color; | ||
| 332 | )"; | ||
| 333 | |||
| 334 | using Uniform = RasterizerOpenGL::PicaShader::Uniform; | ||
| 335 | out += "layout(location = " + std::to_string((int)Uniform::AlphaTestRef) + ") uniform int alphatest_ref;\n"; | ||
| 336 | out += "layout(location = " + std::to_string((int)Uniform::TevConstColors) + ") uniform vec4 const_color[NUM_TEV_STAGES];\n"; | ||
| 337 | out += "layout(location = " + std::to_string((int)Uniform::Texture0) + ") uniform sampler2D tex[3];\n"; | ||
| 338 | out += "layout(location = " + std::to_string((int)Uniform::TevCombinerBufferColor) + ") uniform vec4 tev_combiner_buffer_color;\n"; | ||
| 339 | |||
| 340 | out += "void main() {\n"; | ||
| 341 | out += "vec4 combiner_buffer = tev_combiner_buffer_color;\n"; | ||
| 342 | out += "vec4 last_tex_env_out = vec4(0.0);\n"; | ||
| 343 | |||
| 344 | // Do not do any sort of processing if it's obvious we're not going to pass the alpha test | ||
| 345 | if (config.alpha_test_func == Regs::CompareFunc::Never) { | ||
| 346 | out += "discard; }"; | ||
| 347 | return out; | ||
| 348 | } | ||
| 349 | |||
| 350 | for (size_t index = 0; index < config.tev_stages.size(); ++index) | ||
| 351 | WriteTevStage(out, config, (unsigned)index); | ||
| 352 | |||
| 353 | if (config.alpha_test_func != Regs::CompareFunc::Always) { | ||
| 354 | out += "if ("; | ||
| 355 | AppendAlphaTestCondition(out, config.alpha_test_func); | ||
| 356 | out += ") discard;\n"; | ||
| 357 | } | ||
| 358 | |||
| 359 | out += "color = last_tex_env_out;\n}"; | ||
| 360 | |||
| 361 | return out; | ||
| 362 | } | ||
| 363 | |||
| 364 | std::string GenerateVertexShader() { | ||
| 365 | std::string out = "#version 330\n"; | ||
| 366 | out += "layout(location = " + std::to_string((int)ATTRIBUTE_POSITION) + ") in vec4 vert_position;\n"; | ||
| 367 | out += "layout(location = " + std::to_string((int)ATTRIBUTE_COLOR) + ") in vec4 vert_color;\n"; | ||
| 368 | out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD0) + ") in vec2 vert_texcoord0;\n"; | ||
| 369 | out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD1) + ") in vec2 vert_texcoord1;\n"; | ||
| 370 | out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD2) + ") in vec2 vert_texcoord2;\n"; | ||
| 371 | |||
| 372 | out += R"( | ||
| 373 | out vec4 primary_color; | ||
| 374 | out vec2 texcoord[3]; | ||
| 375 | |||
| 376 | void main() { | ||
| 377 | primary_color = vert_color; | ||
| 378 | texcoord[0] = vert_texcoord0; | ||
| 379 | texcoord[1] = vert_texcoord1; | ||
| 380 | texcoord[2] = vert_texcoord2; | ||
| 381 | gl_Position = vec4(vert_position.x, -vert_position.y, -vert_position.z, vert_position.w); | ||
| 382 | } | ||
| 383 | )"; | ||
| 384 | |||
| 385 | return out; | ||
| 386 | } | ||
| 387 | |||
| 388 | } // namespace GLShader | ||
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.h b/src/video_core/renderer_opengl/gl_shader_gen.h new file mode 100644 index 000000000..0ca9d2879 --- /dev/null +++ b/src/video_core/renderer_opengl/gl_shader_gen.h | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <string> | ||
| 8 | |||
| 9 | #include "video_core/renderer_opengl/gl_rasterizer.h" | ||
| 10 | |||
| 11 | namespace GLShader { | ||
| 12 | |||
| 13 | /** | ||
| 14 | * Generates the GLSL vertex shader program source code for the current Pica state | ||
| 15 | * @returns String of the shader source code | ||
| 16 | */ | ||
| 17 | std::string GenerateVertexShader(); | ||
| 18 | |||
| 19 | /** | ||
| 20 | * Generates the GLSL fragment shader program source code for the current Pica state | ||
| 21 | * @param config ShaderCacheKey object generated for the current Pica state, used for the shader | ||
| 22 | * configuration (NOTE: Use state in this struct only, not the Pica registers!) | ||
| 23 | * @returns String of the shader source code | ||
| 24 | */ | ||
| 25 | std::string GenerateFragmentShader(const PicaShaderConfig& config); | ||
| 26 | |||
| 27 | } // namespace GLShader | ||
diff --git a/src/video_core/renderer_opengl/gl_shader_util.cpp b/src/video_core/renderer_opengl/gl_shader_util.cpp index 4cf246c06..e3f7a5868 100644 --- a/src/video_core/renderer_opengl/gl_shader_util.cpp +++ b/src/video_core/renderer_opengl/gl_shader_util.cpp | |||
| @@ -8,9 +8,9 @@ | |||
| 8 | #include "common/logging/log.h" | 8 | #include "common/logging/log.h" |
| 9 | #include "video_core/renderer_opengl/gl_shader_util.h" | 9 | #include "video_core/renderer_opengl/gl_shader_util.h" |
| 10 | 10 | ||
| 11 | namespace ShaderUtil { | 11 | namespace GLShader { |
| 12 | 12 | ||
| 13 | GLuint LoadShaders(const char* vertex_shader, const char* fragment_shader) { | 13 | GLuint LoadProgram(const char* vertex_shader, const char* fragment_shader) { |
| 14 | 14 | ||
| 15 | // Create the shaders | 15 | // Create the shaders |
| 16 | GLuint vertex_shader_id = glCreateShader(GL_VERTEX_SHADER); | 16 | GLuint vertex_shader_id = glCreateShader(GL_VERTEX_SHADER); |
| @@ -65,6 +65,7 @@ GLuint LoadShaders(const char* vertex_shader, const char* fragment_shader) { | |||
| 65 | GLuint program_id = glCreateProgram(); | 65 | GLuint program_id = glCreateProgram(); |
| 66 | glAttachShader(program_id, vertex_shader_id); | 66 | glAttachShader(program_id, vertex_shader_id); |
| 67 | glAttachShader(program_id, fragment_shader_id); | 67 | glAttachShader(program_id, fragment_shader_id); |
| 68 | |||
| 68 | glLinkProgram(program_id); | 69 | glLinkProgram(program_id); |
| 69 | 70 | ||
| 70 | // Check the program | 71 | // Check the program |
| @@ -87,4 +88,4 @@ GLuint LoadShaders(const char* vertex_shader, const char* fragment_shader) { | |||
| 87 | return program_id; | 88 | return program_id; |
| 88 | } | 89 | } |
| 89 | 90 | ||
| 90 | } | 91 | } // namespace GLShader |
diff --git a/src/video_core/renderer_opengl/gl_shader_util.h b/src/video_core/renderer_opengl/gl_shader_util.h index c9d7cc380..046aae14f 100644 --- a/src/video_core/renderer_opengl/gl_shader_util.h +++ b/src/video_core/renderer_opengl/gl_shader_util.h | |||
| @@ -6,8 +6,22 @@ | |||
| 6 | 6 | ||
| 7 | #include <glad/glad.h> | 7 | #include <glad/glad.h> |
| 8 | 8 | ||
| 9 | namespace ShaderUtil { | 9 | namespace GLShader { |
| 10 | 10 | ||
| 11 | GLuint LoadShaders(const char* vertex_file_path, const char* fragment_file_path); | 11 | enum Attributes { |
| 12 | ATTRIBUTE_POSITION, | ||
| 13 | ATTRIBUTE_COLOR, | ||
| 14 | ATTRIBUTE_TEXCOORD0, | ||
| 15 | ATTRIBUTE_TEXCOORD1, | ||
| 16 | ATTRIBUTE_TEXCOORD2, | ||
| 17 | }; | ||
| 12 | 18 | ||
| 13 | } | 19 | /** |
| 20 | * Utility function to create and compile an OpenGL GLSL shader program (vertex + fragment shader) | ||
| 21 | * @param vertex_shader String of the GLSL vertex shader program | ||
| 22 | * @param fragment_shader String of the GLSL fragment shader program | ||
| 23 | * @returns Handle of the newly created OpenGL shader object | ||
| 24 | */ | ||
| 25 | GLuint LoadProgram(const char* vertex_shader, const char* fragment_shader); | ||
| 26 | |||
| 27 | } // namespace | ||
diff --git a/src/video_core/renderer_opengl/gl_shaders.h b/src/video_core/renderer_opengl/gl_shaders.h deleted file mode 100644 index a8cb2f595..000000000 --- a/src/video_core/renderer_opengl/gl_shaders.h +++ /dev/null | |||
| @@ -1,337 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | namespace GLShaders { | ||
| 8 | |||
| 9 | const char g_vertex_shader[] = R"( | ||
| 10 | #version 150 core | ||
| 11 | |||
| 12 | in vec2 vert_position; | ||
| 13 | in vec2 vert_tex_coord; | ||
| 14 | out vec2 frag_tex_coord; | ||
| 15 | |||
| 16 | // This is a truncated 3x3 matrix for 2D transformations: | ||
| 17 | // The upper-left 2x2 submatrix performs scaling/rotation/mirroring. | ||
| 18 | // The third column performs translation. | ||
| 19 | // The third row could be used for projection, which we don't need in 2D. It hence is assumed to | ||
| 20 | // implicitly be [0, 0, 1] | ||
| 21 | uniform mat3x2 modelview_matrix; | ||
| 22 | |||
| 23 | void main() { | ||
| 24 | // Multiply input position by the rotscale part of the matrix and then manually translate by | ||
| 25 | // the last column. This is equivalent to using a full 3x3 matrix and expanding the vector | ||
| 26 | // to `vec3(vert_position.xy, 1.0)` | ||
| 27 | gl_Position = vec4(mat2(modelview_matrix) * vert_position + modelview_matrix[2], 0.0, 1.0); | ||
| 28 | frag_tex_coord = vert_tex_coord; | ||
| 29 | } | ||
| 30 | )"; | ||
| 31 | |||
| 32 | const char g_fragment_shader[] = R"( | ||
| 33 | #version 150 core | ||
| 34 | |||
| 35 | in vec2 frag_tex_coord; | ||
| 36 | out vec4 color; | ||
| 37 | |||
| 38 | uniform sampler2D color_texture; | ||
| 39 | |||
| 40 | void main() { | ||
| 41 | color = texture(color_texture, frag_tex_coord); | ||
| 42 | } | ||
| 43 | )"; | ||
| 44 | |||
| 45 | const char g_vertex_shader_hw[] = R"( | ||
| 46 | #version 150 core | ||
| 47 | |||
| 48 | #define NUM_VTX_ATTR 7 | ||
| 49 | |||
| 50 | in vec4 vert_position; | ||
| 51 | in vec4 vert_color; | ||
| 52 | in vec2 vert_texcoords[3]; | ||
| 53 | |||
| 54 | out vec4 o[NUM_VTX_ATTR]; | ||
| 55 | |||
| 56 | void main() { | ||
| 57 | o[2] = vert_color; | ||
| 58 | o[3] = vec4(vert_texcoords[0].xy, vert_texcoords[1].xy); | ||
| 59 | o[5] = vec4(0.0, 0.0, vert_texcoords[2].xy); | ||
| 60 | |||
| 61 | gl_Position = vec4(vert_position.x, -vert_position.y, -vert_position.z, vert_position.w); | ||
| 62 | } | ||
| 63 | )"; | ||
| 64 | |||
| 65 | // TODO: Create a shader constructor and cache that builds this program with minimal conditionals instead of using tev_cfg uniforms | ||
| 66 | const char g_fragment_shader_hw[] = R"( | ||
| 67 | #version 150 core | ||
| 68 | |||
| 69 | #define NUM_VTX_ATTR 7 | ||
| 70 | #define NUM_TEV_STAGES 6 | ||
| 71 | |||
| 72 | #define SOURCE_PRIMARYCOLOR 0x0 | ||
| 73 | #define SOURCE_PRIMARYFRAGMENTCOLOR 0x1 | ||
| 74 | #define SOURCE_SECONDARYFRAGMENTCOLOR 0x2 | ||
| 75 | #define SOURCE_TEXTURE0 0x3 | ||
| 76 | #define SOURCE_TEXTURE1 0x4 | ||
| 77 | #define SOURCE_TEXTURE2 0x5 | ||
| 78 | #define SOURCE_TEXTURE3 0x6 | ||
| 79 | #define SOURCE_PREVIOUSBUFFER 0xd | ||
| 80 | #define SOURCE_CONSTANT 0xe | ||
| 81 | #define SOURCE_PREVIOUS 0xf | ||
| 82 | |||
| 83 | #define COLORMODIFIER_SOURCECOLOR 0x0 | ||
| 84 | #define COLORMODIFIER_ONEMINUSSOURCECOLOR 0x1 | ||
| 85 | #define COLORMODIFIER_SOURCEALPHA 0x2 | ||
| 86 | #define COLORMODIFIER_ONEMINUSSOURCEALPHA 0x3 | ||
| 87 | #define COLORMODIFIER_SOURCERED 0x4 | ||
| 88 | #define COLORMODIFIER_ONEMINUSSOURCERED 0x5 | ||
| 89 | #define COLORMODIFIER_SOURCEGREEN 0x8 | ||
| 90 | #define COLORMODIFIER_ONEMINUSSOURCEGREEN 0x9 | ||
| 91 | #define COLORMODIFIER_SOURCEBLUE 0xc | ||
| 92 | #define COLORMODIFIER_ONEMINUSSOURCEBLUE 0xd | ||
| 93 | |||
| 94 | #define ALPHAMODIFIER_SOURCEALPHA 0x0 | ||
| 95 | #define ALPHAMODIFIER_ONEMINUSSOURCEALPHA 0x1 | ||
| 96 | #define ALPHAMODIFIER_SOURCERED 0x2 | ||
| 97 | #define ALPHAMODIFIER_ONEMINUSSOURCERED 0x3 | ||
| 98 | #define ALPHAMODIFIER_SOURCEGREEN 0x4 | ||
| 99 | #define ALPHAMODIFIER_ONEMINUSSOURCEGREEN 0x5 | ||
| 100 | #define ALPHAMODIFIER_SOURCEBLUE 0x6 | ||
| 101 | #define ALPHAMODIFIER_ONEMINUSSOURCEBLUE 0x7 | ||
| 102 | |||
| 103 | #define OPERATION_REPLACE 0 | ||
| 104 | #define OPERATION_MODULATE 1 | ||
| 105 | #define OPERATION_ADD 2 | ||
| 106 | #define OPERATION_ADDSIGNED 3 | ||
| 107 | #define OPERATION_LERP 4 | ||
| 108 | #define OPERATION_SUBTRACT 5 | ||
| 109 | #define OPERATION_MULTIPLYTHENADD 8 | ||
| 110 | #define OPERATION_ADDTHENMULTIPLY 9 | ||
| 111 | |||
| 112 | #define COMPAREFUNC_NEVER 0 | ||
| 113 | #define COMPAREFUNC_ALWAYS 1 | ||
| 114 | #define COMPAREFUNC_EQUAL 2 | ||
| 115 | #define COMPAREFUNC_NOTEQUAL 3 | ||
| 116 | #define COMPAREFUNC_LESSTHAN 4 | ||
| 117 | #define COMPAREFUNC_LESSTHANOREQUAL 5 | ||
| 118 | #define COMPAREFUNC_GREATERTHAN 6 | ||
| 119 | #define COMPAREFUNC_GREATERTHANOREQUAL 7 | ||
| 120 | |||
| 121 | in vec4 o[NUM_VTX_ATTR]; | ||
| 122 | out vec4 color; | ||
| 123 | |||
| 124 | uniform bool alphatest_enabled; | ||
| 125 | uniform int alphatest_func; | ||
| 126 | uniform float alphatest_ref; | ||
| 127 | |||
| 128 | uniform sampler2D tex[3]; | ||
| 129 | |||
| 130 | uniform vec4 tev_combiner_buffer_color; | ||
| 131 | |||
| 132 | struct TEVConfig | ||
| 133 | { | ||
| 134 | bool enabled; | ||
| 135 | ivec3 color_sources; | ||
| 136 | ivec3 alpha_sources; | ||
| 137 | ivec3 color_modifiers; | ||
| 138 | ivec3 alpha_modifiers; | ||
| 139 | ivec2 color_alpha_op; | ||
| 140 | ivec2 color_alpha_multiplier; | ||
| 141 | vec4 const_color; | ||
| 142 | bvec2 updates_combiner_buffer_color_alpha; | ||
| 143 | }; | ||
| 144 | |||
| 145 | uniform TEVConfig tev_cfgs[NUM_TEV_STAGES]; | ||
| 146 | |||
| 147 | vec4 g_combiner_buffer; | ||
| 148 | vec4 g_last_tex_env_out; | ||
| 149 | vec4 g_const_color; | ||
| 150 | |||
| 151 | vec4 GetSource(int source) { | ||
| 152 | if (source == SOURCE_PRIMARYCOLOR) { | ||
| 153 | return o[2]; | ||
| 154 | } else if (source == SOURCE_PRIMARYFRAGMENTCOLOR) { | ||
| 155 | // HACK: Until we implement fragment lighting, use primary_color | ||
| 156 | return o[2]; | ||
| 157 | } else if (source == SOURCE_SECONDARYFRAGMENTCOLOR) { | ||
| 158 | // HACK: Until we implement fragment lighting, use zero | ||
| 159 | return vec4(0.0, 0.0, 0.0, 0.0); | ||
| 160 | } else if (source == SOURCE_TEXTURE0) { | ||
| 161 | return texture(tex[0], o[3].xy); | ||
| 162 | } else if (source == SOURCE_TEXTURE1) { | ||
| 163 | return texture(tex[1], o[3].zw); | ||
| 164 | } else if (source == SOURCE_TEXTURE2) { | ||
| 165 | // TODO: Unverified | ||
| 166 | return texture(tex[2], o[5].zw); | ||
| 167 | } else if (source == SOURCE_TEXTURE3) { | ||
| 168 | // TODO: no 4th texture? | ||
| 169 | } else if (source == SOURCE_PREVIOUSBUFFER) { | ||
| 170 | return g_combiner_buffer; | ||
| 171 | } else if (source == SOURCE_CONSTANT) { | ||
| 172 | return g_const_color; | ||
| 173 | } else if (source == SOURCE_PREVIOUS) { | ||
| 174 | return g_last_tex_env_out; | ||
| 175 | } | ||
| 176 | |||
| 177 | return vec4(0.0); | ||
| 178 | } | ||
| 179 | |||
| 180 | vec3 GetColorModifier(int factor, vec4 color) { | ||
| 181 | if (factor == COLORMODIFIER_SOURCECOLOR) { | ||
| 182 | return color.rgb; | ||
| 183 | } else if (factor == COLORMODIFIER_ONEMINUSSOURCECOLOR) { | ||
| 184 | return vec3(1.0) - color.rgb; | ||
| 185 | } else if (factor == COLORMODIFIER_SOURCEALPHA) { | ||
| 186 | return color.aaa; | ||
| 187 | } else if (factor == COLORMODIFIER_ONEMINUSSOURCEALPHA) { | ||
| 188 | return vec3(1.0) - color.aaa; | ||
| 189 | } else if (factor == COLORMODIFIER_SOURCERED) { | ||
| 190 | return color.rrr; | ||
| 191 | } else if (factor == COLORMODIFIER_ONEMINUSSOURCERED) { | ||
| 192 | return vec3(1.0) - color.rrr; | ||
| 193 | } else if (factor == COLORMODIFIER_SOURCEGREEN) { | ||
| 194 | return color.ggg; | ||
| 195 | } else if (factor == COLORMODIFIER_ONEMINUSSOURCEGREEN) { | ||
| 196 | return vec3(1.0) - color.ggg; | ||
| 197 | } else if (factor == COLORMODIFIER_SOURCEBLUE) { | ||
| 198 | return color.bbb; | ||
| 199 | } else if (factor == COLORMODIFIER_ONEMINUSSOURCEBLUE) { | ||
| 200 | return vec3(1.0) - color.bbb; | ||
| 201 | } | ||
| 202 | |||
| 203 | return vec3(0.0); | ||
| 204 | } | ||
| 205 | |||
| 206 | float GetAlphaModifier(int factor, vec4 color) { | ||
| 207 | if (factor == ALPHAMODIFIER_SOURCEALPHA) { | ||
| 208 | return color.a; | ||
| 209 | } else if (factor == ALPHAMODIFIER_ONEMINUSSOURCEALPHA) { | ||
| 210 | return 1.0 - color.a; | ||
| 211 | } else if (factor == ALPHAMODIFIER_SOURCERED) { | ||
| 212 | return color.r; | ||
| 213 | } else if (factor == ALPHAMODIFIER_ONEMINUSSOURCERED) { | ||
| 214 | return 1.0 - color.r; | ||
| 215 | } else if (factor == ALPHAMODIFIER_SOURCEGREEN) { | ||
| 216 | return color.g; | ||
| 217 | } else if (factor == ALPHAMODIFIER_ONEMINUSSOURCEGREEN) { | ||
| 218 | return 1.0 - color.g; | ||
| 219 | } else if (factor == ALPHAMODIFIER_SOURCEBLUE) { | ||
| 220 | return color.b; | ||
| 221 | } else if (factor == ALPHAMODIFIER_ONEMINUSSOURCEBLUE) { | ||
| 222 | return 1.0 - color.b; | ||
| 223 | } | ||
| 224 | |||
| 225 | return 0.0; | ||
| 226 | } | ||
| 227 | |||
| 228 | vec3 ColorCombine(int op, vec3 color[3]) { | ||
| 229 | if (op == OPERATION_REPLACE) { | ||
| 230 | return color[0]; | ||
| 231 | } else if (op == OPERATION_MODULATE) { | ||
| 232 | return color[0] * color[1]; | ||
| 233 | } else if (op == OPERATION_ADD) { | ||
| 234 | return min(color[0] + color[1], 1.0); | ||
| 235 | } else if (op == OPERATION_ADDSIGNED) { | ||
| 236 | return clamp(color[0] + color[1] - vec3(0.5), 0.0, 1.0); | ||
| 237 | } else if (op == OPERATION_LERP) { | ||
| 238 | return color[0] * color[2] + color[1] * (vec3(1.0) - color[2]); | ||
| 239 | } else if (op == OPERATION_SUBTRACT) { | ||
| 240 | return max(color[0] - color[1], 0.0); | ||
| 241 | } else if (op == OPERATION_MULTIPLYTHENADD) { | ||
| 242 | return min(color[0] * color[1] + color[2], 1.0); | ||
| 243 | } else if (op == OPERATION_ADDTHENMULTIPLY) { | ||
| 244 | return min(color[0] + color[1], 1.0) * color[2]; | ||
| 245 | } | ||
| 246 | |||
| 247 | return vec3(0.0); | ||
| 248 | } | ||
| 249 | |||
| 250 | float AlphaCombine(int op, float alpha[3]) { | ||
| 251 | if (op == OPERATION_REPLACE) { | ||
| 252 | return alpha[0]; | ||
| 253 | } else if (op == OPERATION_MODULATE) { | ||
| 254 | return alpha[0] * alpha[1]; | ||
| 255 | } else if (op == OPERATION_ADD) { | ||
| 256 | return min(alpha[0] + alpha[1], 1.0); | ||
| 257 | } else if (op == OPERATION_ADDSIGNED) { | ||
| 258 | return clamp(alpha[0] + alpha[1] - 0.5, 0.0, 1.0); | ||
| 259 | } else if (op == OPERATION_LERP) { | ||
| 260 | return alpha[0] * alpha[2] + alpha[1] * (1.0 - alpha[2]); | ||
| 261 | } else if (op == OPERATION_SUBTRACT) { | ||
| 262 | return max(alpha[0] - alpha[1], 0.0); | ||
| 263 | } else if (op == OPERATION_MULTIPLYTHENADD) { | ||
| 264 | return min(alpha[0] * alpha[1] + alpha[2], 1.0); | ||
| 265 | } else if (op == OPERATION_ADDTHENMULTIPLY) { | ||
| 266 | return min(alpha[0] + alpha[1], 1.0) * alpha[2]; | ||
| 267 | } | ||
| 268 | |||
| 269 | return 0.0; | ||
| 270 | } | ||
| 271 | |||
| 272 | void main(void) { | ||
| 273 | g_combiner_buffer = tev_combiner_buffer_color; | ||
| 274 | |||
| 275 | for (int tex_env_idx = 0; tex_env_idx < NUM_TEV_STAGES; ++tex_env_idx) { | ||
| 276 | if (tev_cfgs[tex_env_idx].enabled) { | ||
| 277 | g_const_color = tev_cfgs[tex_env_idx].const_color; | ||
| 278 | |||
| 279 | vec3 color_results[3] = vec3[3](GetColorModifier(tev_cfgs[tex_env_idx].color_modifiers.x, GetSource(tev_cfgs[tex_env_idx].color_sources.x)), | ||
| 280 | GetColorModifier(tev_cfgs[tex_env_idx].color_modifiers.y, GetSource(tev_cfgs[tex_env_idx].color_sources.y)), | ||
| 281 | GetColorModifier(tev_cfgs[tex_env_idx].color_modifiers.z, GetSource(tev_cfgs[tex_env_idx].color_sources.z))); | ||
| 282 | vec3 color_output = ColorCombine(tev_cfgs[tex_env_idx].color_alpha_op.x, color_results); | ||
| 283 | |||
| 284 | float alpha_results[3] = float[3](GetAlphaModifier(tev_cfgs[tex_env_idx].alpha_modifiers.x, GetSource(tev_cfgs[tex_env_idx].alpha_sources.x)), | ||
| 285 | GetAlphaModifier(tev_cfgs[tex_env_idx].alpha_modifiers.y, GetSource(tev_cfgs[tex_env_idx].alpha_sources.y)), | ||
| 286 | GetAlphaModifier(tev_cfgs[tex_env_idx].alpha_modifiers.z, GetSource(tev_cfgs[tex_env_idx].alpha_sources.z))); | ||
| 287 | float alpha_output = AlphaCombine(tev_cfgs[tex_env_idx].color_alpha_op.y, alpha_results); | ||
| 288 | |||
| 289 | g_last_tex_env_out = vec4(min(color_output * tev_cfgs[tex_env_idx].color_alpha_multiplier.x, 1.0), min(alpha_output * tev_cfgs[tex_env_idx].color_alpha_multiplier.y, 1.0)); | ||
| 290 | } | ||
| 291 | |||
| 292 | if (tev_cfgs[tex_env_idx].updates_combiner_buffer_color_alpha.x) { | ||
| 293 | g_combiner_buffer.rgb = g_last_tex_env_out.rgb; | ||
| 294 | } | ||
| 295 | |||
| 296 | if (tev_cfgs[tex_env_idx].updates_combiner_buffer_color_alpha.y) { | ||
| 297 | g_combiner_buffer.a = g_last_tex_env_out.a; | ||
| 298 | } | ||
| 299 | } | ||
| 300 | |||
| 301 | if (alphatest_enabled) { | ||
| 302 | if (alphatest_func == COMPAREFUNC_NEVER) { | ||
| 303 | discard; | ||
| 304 | } else if (alphatest_func == COMPAREFUNC_ALWAYS) { | ||
| 305 | |||
| 306 | } else if (alphatest_func == COMPAREFUNC_EQUAL) { | ||
| 307 | if (g_last_tex_env_out.a != alphatest_ref) { | ||
| 308 | discard; | ||
| 309 | } | ||
| 310 | } else if (alphatest_func == COMPAREFUNC_NOTEQUAL) { | ||
| 311 | if (g_last_tex_env_out.a == alphatest_ref) { | ||
| 312 | discard; | ||
| 313 | } | ||
| 314 | } else if (alphatest_func == COMPAREFUNC_LESSTHAN) { | ||
| 315 | if (g_last_tex_env_out.a >= alphatest_ref) { | ||
| 316 | discard; | ||
| 317 | } | ||
| 318 | } else if (alphatest_func == COMPAREFUNC_LESSTHANOREQUAL) { | ||
| 319 | if (g_last_tex_env_out.a > alphatest_ref) { | ||
| 320 | discard; | ||
| 321 | } | ||
| 322 | } else if (alphatest_func == COMPAREFUNC_GREATERTHAN) { | ||
| 323 | if (g_last_tex_env_out.a <= alphatest_ref) { | ||
| 324 | discard; | ||
| 325 | } | ||
| 326 | } else if (alphatest_func == COMPAREFUNC_GREATERTHANOREQUAL) { | ||
| 327 | if (g_last_tex_env_out.a < alphatest_ref) { | ||
| 328 | discard; | ||
| 329 | } | ||
| 330 | } | ||
| 331 | } | ||
| 332 | |||
| 333 | color = g_last_tex_env_out; | ||
| 334 | } | ||
| 335 | )"; | ||
| 336 | |||
| 337 | } | ||
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h index 6ecbedbb4..668b04259 100644 --- a/src/video_core/renderer_opengl/gl_state.h +++ b/src/video_core/renderer_opengl/gl_state.h | |||
| @@ -65,6 +65,7 @@ public: | |||
| 65 | GLuint vertex_array; // GL_VERTEX_ARRAY_BINDING | 65 | GLuint vertex_array; // GL_VERTEX_ARRAY_BINDING |
| 66 | GLuint vertex_buffer; // GL_ARRAY_BUFFER_BINDING | 66 | GLuint vertex_buffer; // GL_ARRAY_BUFFER_BINDING |
| 67 | GLuint shader_program; // GL_CURRENT_PROGRAM | 67 | GLuint shader_program; // GL_CURRENT_PROGRAM |
| 68 | bool shader_dirty; | ||
| 68 | } draw; | 69 | } draw; |
| 69 | 70 | ||
| 70 | OpenGLState(); | 71 | OpenGLState(); |
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index f1313b54f..ac0a058db 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp | |||
| @@ -21,9 +21,44 @@ | |||
| 21 | #include "video_core/debug_utils/debug_utils.h" | 21 | #include "video_core/debug_utils/debug_utils.h" |
| 22 | #include "video_core/renderer_opengl/gl_rasterizer.h" | 22 | #include "video_core/renderer_opengl/gl_rasterizer.h" |
| 23 | #include "video_core/renderer_opengl/gl_shader_util.h" | 23 | #include "video_core/renderer_opengl/gl_shader_util.h" |
| 24 | #include "video_core/renderer_opengl/gl_shaders.h" | ||
| 25 | #include "video_core/renderer_opengl/renderer_opengl.h" | 24 | #include "video_core/renderer_opengl/renderer_opengl.h" |
| 26 | 25 | ||
| 26 | static const char vertex_shader[] = R"( | ||
| 27 | #version 150 core | ||
| 28 | |||
| 29 | in vec2 vert_position; | ||
| 30 | in vec2 vert_tex_coord; | ||
| 31 | out vec2 frag_tex_coord; | ||
| 32 | |||
| 33 | // This is a truncated 3x3 matrix for 2D transformations: | ||
| 34 | // The upper-left 2x2 submatrix performs scaling/rotation/mirroring. | ||
| 35 | // The third column performs translation. | ||
| 36 | // The third row could be used for projection, which we don't need in 2D. It hence is assumed to | ||
| 37 | // implicitly be [0, 0, 1] | ||
| 38 | uniform mat3x2 modelview_matrix; | ||
| 39 | |||
| 40 | void main() { | ||
| 41 | // Multiply input position by the rotscale part of the matrix and then manually translate by | ||
| 42 | // the last column. This is equivalent to using a full 3x3 matrix and expanding the vector | ||
| 43 | // to `vec3(vert_position.xy, 1.0)` | ||
| 44 | gl_Position = vec4(mat2(modelview_matrix) * vert_position + modelview_matrix[2], 0.0, 1.0); | ||
| 45 | frag_tex_coord = vert_tex_coord; | ||
| 46 | } | ||
| 47 | )"; | ||
| 48 | |||
| 49 | static const char fragment_shader[] = R"( | ||
| 50 | #version 150 core | ||
| 51 | |||
| 52 | in vec2 frag_tex_coord; | ||
| 53 | out vec4 color; | ||
| 54 | |||
| 55 | uniform sampler2D color_texture; | ||
| 56 | |||
| 57 | void main() { | ||
| 58 | color = texture(color_texture, frag_tex_coord); | ||
| 59 | } | ||
| 60 | )"; | ||
| 61 | |||
| 27 | /** | 62 | /** |
| 28 | * Vertex structure that the drawn screen rectangles are composed of. | 63 | * Vertex structure that the drawn screen rectangles are composed of. |
| 29 | */ | 64 | */ |
| @@ -207,7 +242,7 @@ void RendererOpenGL::InitOpenGLObjects() { | |||
| 207 | glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue, 0.0f); | 242 | glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue, 0.0f); |
| 208 | 243 | ||
| 209 | // Link shaders and get variable locations | 244 | // Link shaders and get variable locations |
| 210 | program_id = ShaderUtil::LoadShaders(GLShaders::g_vertex_shader, GLShaders::g_fragment_shader); | 245 | program_id = GLShader::LoadProgram(vertex_shader, fragment_shader); |
| 211 | uniform_modelview_matrix = glGetUniformLocation(program_id, "modelview_matrix"); | 246 | uniform_modelview_matrix = glGetUniformLocation(program_id, "modelview_matrix"); |
| 212 | uniform_color_texture = glGetUniformLocation(program_id, "color_texture"); | 247 | uniform_color_texture = glGetUniformLocation(program_id, "color_texture"); |
| 213 | attrib_position = glGetAttribLocation(program_id, "vert_position"); | 248 | attrib_position = glGetAttribLocation(program_id, "vert_position"); |