summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CONTRIBUTING.md6
-rw-r--r--appveyor.yml8
-rw-r--r--src/citra_qt/CMakeLists.txt8
-rw-r--r--src/citra_qt/debugger/callstack.ui3
-rw-r--r--src/common/math_util.h2
-rw-r--r--src/core/arm/skyeye_common/arm_regformat.h2
-rw-r--r--src/core/arm/skyeye_common/vfp/vfp.cpp4
-rw-r--r--src/core/arm/skyeye_common/vfp/vfp.h1
-rw-r--r--src/core/arm/skyeye_common/vfp/vfpinstr.cpp18
-rw-r--r--src/core/hle/function_wrappers.h17
-rw-r--r--src/core/hle/kernel/event.cpp3
-rw-r--r--src/core/hle/kernel/kernel.cpp22
-rw-r--r--src/core/hle/kernel/kernel.h6
-rw-r--r--src/core/hle/kernel/mutex.cpp9
-rw-r--r--src/core/hle/kernel/semaphore.cpp8
-rw-r--r--src/core/hle/kernel/thread.cpp76
-rw-r--r--src/core/hle/kernel/thread.h14
-rw-r--r--src/core/hle/svc.cpp26
-rw-r--r--src/core/hw/hw.cpp2
-rw-r--r--src/video_core/pica.h6
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp154
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp36
-rw-r--r--src/video_core/renderer_opengl/gl_state.h7
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp8
24 files changed, 246 insertions, 200 deletions
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index c8c8e3884..906a4bc7d 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -10,16 +10,16 @@ Citra is a brand new project, so we have a great opportunity to keep things clea
10 10
11### Naming Rules 11### Naming Rules
12* Functions 12* Functions
13 * CamelCase, "_" may also be used for clarity (e.g. ARM_InitCore) 13 * PascalCase, "_" may also be used for clarity (e.g. ARM_InitCore)
14* Variables 14* Variables
15 * lower_case_underscored 15 * lower_case_underscored
16 * Prefix "g_" if global 16 * Prefix "g_" if global
17* Classes 17* Classes
18 * CamelCase, "_" may also be used for clarity (e.g. OGL_VideoInterface) 18 * PascalCase, "_" may also be used for clarity (e.g. OGL_VideoInterface)
19* Files/Folders 19* Files/Folders
20 * lower_case_underscored 20 * lower_case_underscored
21* Namespaces 21* Namespaces
22 * CamelCase, "_" may also be used for clarity (e.g. ARM_InitCore) 22 * PascalCase, "_" may also be used for clarity (e.g. ARM_InitCore)
23 23
24### Indentation/Whitespace Style 24### Indentation/Whitespace Style
25Follow the indentation/whitespace style shown below. Do not use tabs, use 4-spaces instead. 25Follow the indentation/whitespace style shown below. Do not use tabs, use 4-spaces instead.
diff --git a/appveyor.yml b/appveyor.yml
index 46362d1b4..8b420f20c 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -33,12 +33,15 @@ after_build:
33 $GITREV = $(git show -s --format='%h') 33 $GITREV = $(git show -s --format='%h')
34 # Where are these spaces coming from? Regardless, let's remove them 34 # Where are these spaces coming from? Regardless, let's remove them
35 $BUILD_NAME = "citra-${GITDATE}-${GITREV}-windows-amd64.7z" -replace " ","" 35 $BUILD_NAME = "citra-${GITDATE}-${GITREV}-windows-amd64.7z" -replace " ",""
36 $BUILD_NAME_NOQT = "citra-noqt-${GITDATE}-${GITREV}-windows-amd64.7z" -replace " ",""
36 # Zip up the build folder 37 # Zip up the build folder
37 7z a $BUILD_NAME .\build\bin\release\* 38 7z a $BUILD_NAME .\build\bin\release\*
39 # Do a second archive with only the binaries
40 7z a $BUILD_NAME_NOQT .\build\bin\release\*.exe
38 41
39 # Download winscp 42 # Download winscp
40 Invoke-WebRequest "http://hivelocity.dl.sourceforge.net/project/winscp/WinSCP/5.7/winscp570.zip" -OutFile "winscp570.zip" 43 Invoke-WebRequest "https://cdn.winscp.net/files/winscp573.zip?secure=yE1jHlRoBZTA0htWnu1OVQ==,1434405422" -OutFile "winscp573.zip"
41 7z e -y winscp570.zip 44 7z e -y winscp573.zip
42 45
43 # Upload to server 46 # Upload to server
44 .\WinSCP.com /command ` 47 .\WinSCP.com /command `
@@ -46,5 +49,6 @@ after_build:
46 "option confirm off" ` 49 "option confirm off" `
47 "open sftp://citra-builds:${env:BUILD_PASSWORD}@builds.citra-emu.org -hostkey=*" ` 50 "open sftp://citra-builds:${env:BUILD_PASSWORD}@builds.citra-emu.org -hostkey=*" `
48 "put $BUILD_NAME /citra/nightly/windows-amd64/" ` 51 "put $BUILD_NAME /citra/nightly/windows-amd64/" `
52 "put $BUILD_NAME_NOQT /citra/nightly/windows-noqt-amd64/" `
49 "exit" 53 "exit"
50 } 54 }
diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt
index c05779380..c2d1ad240 100644
--- a/src/citra_qt/CMakeLists.txt
+++ b/src/citra_qt/CMakeLists.txt
@@ -91,10 +91,10 @@ if (Qt5_FOUND AND MSVC)
91 set(PLATFORMS ${DLL_DEST}platforms/) 91 set(PLATFORMS ${DLL_DEST}platforms/)
92 92
93 # windows commandline expects the / to be \ so switch them 93 # windows commandline expects the / to be \ so switch them
94 string(REPLACE "/" "\\" Qt5_DLL_DIR ${Qt5_DLL_DIR}) 94 string(REPLACE "/" "\\\\" Qt5_DLL_DIR ${Qt5_DLL_DIR})
95 string(REPLACE "/" "\\" Qt5_PLATFORMS_DIR ${Qt5_PLATFORMS_DIR}) 95 string(REPLACE "/" "\\\\" Qt5_PLATFORMS_DIR ${Qt5_PLATFORMS_DIR})
96 string(REPLACE "/" "\\" DLL_DEST ${DLL_DEST}) 96 string(REPLACE "/" "\\\\" DLL_DEST ${DLL_DEST})
97 string(REPLACE "/" "\\" PLATFORMS ${PLATFORMS}) 97 string(REPLACE "/" "\\\\" PLATFORMS ${PLATFORMS})
98 98
99 # /NJH /NJS /NDL /NFL /NC /NS /NP - Silence any output 99 # /NJH /NJS /NDL /NFL /NC /NS /NP - Silence any output
100 # cmake adds an extra check for command success which doesn't work too well with robocopy 100 # cmake adds an extra check for command success which doesn't work too well with robocopy
diff --git a/src/citra_qt/debugger/callstack.ui b/src/citra_qt/debugger/callstack.ui
index b0e31120f..248ea3dd7 100644
--- a/src/citra_qt/debugger/callstack.ui
+++ b/src/citra_qt/debugger/callstack.ui
@@ -17,6 +17,9 @@
17 <layout class="QVBoxLayout" name="verticalLayout"> 17 <layout class="QVBoxLayout" name="verticalLayout">
18 <item> 18 <item>
19 <widget class="QTreeView" name="treeView"> 19 <widget class="QTreeView" name="treeView">
20 <property name="editTriggers">
21 <set>QAbstractItemView::NoEditTriggers</set>
22 </property>
20 <property name="alternatingRowColors"> 23 <property name="alternatingRowColors">
21 <bool>true</bool> 24 <bool>true</bool>
22 </property> 25 </property>
diff --git a/src/common/math_util.h b/src/common/math_util.h
index 4b0910741..d44b06e74 100644
--- a/src/common/math_util.h
+++ b/src/common/math_util.h
@@ -12,7 +12,7 @@ namespace MathUtil
12{ 12{
13 13
14inline bool IntervalsIntersect(unsigned start0, unsigned length0, unsigned start1, unsigned length1) { 14inline bool IntervalsIntersect(unsigned start0, unsigned length0, unsigned start1, unsigned length1) {
15 return (std::max(start0, start1) <= std::min(start0 + length0, start1 + length1)); 15 return (std::max(start0, start1) < std::min(start0 + length0, start1 + length1));
16} 16}
17 17
18template<typename T> 18template<typename T>
diff --git a/src/core/arm/skyeye_common/arm_regformat.h b/src/core/arm/skyeye_common/arm_regformat.h
index 6c89774eb..a92effbb4 100644
--- a/src/core/arm/skyeye_common/arm_regformat.h
+++ b/src/core/arm/skyeye_common/arm_regformat.h
@@ -59,6 +59,8 @@ enum {
59 VFP_FPSID, 59 VFP_FPSID,
60 VFP_FPSCR, 60 VFP_FPSCR,
61 VFP_FPEXC, 61 VFP_FPEXC,
62 VFP_MVFR0,
63 VFP_MVFR1,
62 64
63 // Not an actual register. 65 // Not an actual register.
64 // All VFP system registers should be defined above this. 66 // All VFP system registers should be defined above this.
diff --git a/src/core/arm/skyeye_common/vfp/vfp.cpp b/src/core/arm/skyeye_common/vfp/vfp.cpp
index b88d47750..571d6c2f2 100644
--- a/src/core/arm/skyeye_common/vfp/vfp.cpp
+++ b/src/core/arm/skyeye_common/vfp/vfp.cpp
@@ -33,6 +33,10 @@ unsigned VFPInit(ARMul_State* state)
33 state->VFP[VFP_FPEXC] = 0; 33 state->VFP[VFP_FPEXC] = 0;
34 state->VFP[VFP_FPSCR] = 0; 34 state->VFP[VFP_FPSCR] = 0;
35 35
36 // ARM11 MPCore feature register values.
37 state->VFP[VFP_MVFR0] = 0x11111111;
38 state->VFP[VFP_MVFR1] = 0;
39
36 return 0; 40 return 0;
37} 41}
38 42
diff --git a/src/core/arm/skyeye_common/vfp/vfp.h b/src/core/arm/skyeye_common/vfp/vfp.h
index 727350f14..acefae9bb 100644
--- a/src/core/arm/skyeye_common/vfp/vfp.h
+++ b/src/core/arm/skyeye_common/vfp/vfp.h
@@ -22,7 +22,6 @@
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_UNIMPLEMENTED(x) LOG_ERROR(Core_ARM11, "in func %s, " #x " unimplemented\n", __FUNCTION__); exit(-1);
26#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\n", __FUNCTION__);
27#define CHECK_VFP_ENABLED 26#define CHECK_VFP_ENABLED
28#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]);
diff --git a/src/core/arm/skyeye_common/vfp/vfpinstr.cpp b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp
index 3ed918a93..67fe63aa4 100644
--- a/src/core/arm/skyeye_common/vfp/vfpinstr.cpp
+++ b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp
@@ -1068,10 +1068,12 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovbrc)(unsigned int inst, int index)
1068#ifdef VFP_INTERPRETER_IMPL 1068#ifdef VFP_INTERPRETER_IMPL
1069VMOVBRC_INST: 1069VMOVBRC_INST:
1070{ 1070{
1071 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 1071 if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
1072 CHECK_VFP_ENABLED; 1072 CHECK_VFP_ENABLED;
1073 1073
1074 VFP_DEBUG_UNIMPLEMENTED(VMOVBRC); 1074 vmovbrc_inst* const inst_cream = (vmovbrc_inst*)inst_base->component;
1075
1076 cpu->ExtReg[(2 * inst_cream->d) + inst_cream->index] = cpu->Reg[inst_cream->t];
1075 } 1077 }
1076 cpu->Reg[15] += GET_INST_SIZE(cpu); 1078 cpu->Reg[15] += GET_INST_SIZE(cpu);
1077 INC_PC(sizeof(vmovbrc_inst)); 1079 INC_PC(sizeof(vmovbrc_inst));
@@ -1139,12 +1141,10 @@ VMRS_INST:
1139 cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_FPSID]; 1141 cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_FPSID];
1140 break; 1142 break;
1141 case 6: 1143 case 6:
1142 /* MVFR1, VFPv3 only ? */ 1144 cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_MVFR1];
1143 LOG_TRACE(Core_ARM11, "\tr%d <= MVFR1 unimplemented\n", inst_cream->Rt);
1144 break; 1145 break;
1145 case 7: 1146 case 7:
1146 /* MVFR0, VFPv3 only? */ 1147 cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_MVFR0];
1147 LOG_TRACE(Core_ARM11, "\tr%d <= MVFR0 unimplemented\n", inst_cream->Rt);
1148 break; 1148 break;
1149 case 8: 1149 case 8:
1150 cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_FPEXC]; 1150 cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_FPEXC];
@@ -1195,10 +1195,12 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovbcr)(unsigned int inst, int index)
1195#ifdef VFP_INTERPRETER_IMPL 1195#ifdef VFP_INTERPRETER_IMPL
1196VMOVBCR_INST: 1196VMOVBCR_INST:
1197{ 1197{
1198 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 1198 if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
1199 CHECK_VFP_ENABLED; 1199 CHECK_VFP_ENABLED;
1200 1200
1201 VFP_DEBUG_UNIMPLEMENTED(VMOVBCR); 1201 vmovbcr_inst* const inst_cream = (vmovbcr_inst*) inst_base->component;
1202
1203 cpu->Reg[inst_cream->t] = cpu->ExtReg[(2 * inst_cream->d) + inst_cream->index];
1202 } 1204 }
1203 cpu->Reg[15] += GET_INST_SIZE(cpu); 1205 cpu->Reg[15] += GET_INST_SIZE(cpu);
1204 INC_PC(sizeof(vmovbcr_inst)); 1206 INC_PC(sizeof(vmovbcr_inst));
diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h
index 23c86a72d..5949cb470 100644
--- a/src/core/hle/function_wrappers.h
+++ b/src/core/hle/function_wrappers.h
@@ -9,11 +9,15 @@
9#include "core/arm/arm_interface.h" 9#include "core/arm/arm_interface.h"
10#include "core/memory.h" 10#include "core/memory.h"
11#include "core/hle/hle.h" 11#include "core/hle/hle.h"
12#include "core/hle/result.h"
12 13
13namespace HLE { 14namespace HLE {
14 15
15#define PARAM(n) Core::g_app_core->GetReg(n) 16#define PARAM(n) Core::g_app_core->GetReg(n)
16 17
18/// An invalid result code that is meant to be overwritten when a thread resumes from waiting
19static const ResultCode RESULT_INVALID(0xDEADC0DE);
20
17/** 21/**
18 * HLE a function return from the current ARM11 userland process 22 * HLE a function return from the current ARM11 userland process
19 * @param res Result to return 23 * @param res Result to return
@@ -57,8 +61,11 @@ template<ResultCode func(s32*, u32*, s32, bool, s64)> void Wrap() {
57 s32 param_1 = 0; 61 s32 param_1 = 0;
58 s32 retval = func(&param_1, (Handle*)Memory::GetPointer(PARAM(1)), (s32)PARAM(2), 62 s32 retval = func(&param_1, (Handle*)Memory::GetPointer(PARAM(1)), (s32)PARAM(2),
59 (PARAM(3) != 0), (((s64)PARAM(4) << 32) | PARAM(0))).raw; 63 (PARAM(3) != 0), (((s64)PARAM(4) << 32) | PARAM(0))).raw;
60 Core::g_app_core->SetReg(1, (u32)param_1); 64
61 FuncReturn(retval); 65 if (retval != RESULT_INVALID.raw) {
66 Core::g_app_core->SetReg(1, (u32)param_1);
67 FuncReturn(retval);
68 }
62} 69}
63 70
64template<ResultCode func(u32, u32, u32, u32, s64)> void Wrap() { 71template<ResultCode func(u32, u32, u32, u32, s64)> void Wrap() {
@@ -73,7 +80,11 @@ template<ResultCode func(u32*)> void Wrap(){
73} 80}
74 81
75template<ResultCode func(u32, s64)> void Wrap() { 82template<ResultCode func(u32, s64)> void Wrap() {
76 FuncReturn(func(PARAM(0), (((s64)PARAM(3) << 32) | PARAM(2))).raw); 83 s32 retval = func(PARAM(0), (((s64)PARAM(3) << 32) | PARAM(2))).raw;
84
85 if (retval != RESULT_INVALID.raw) {
86 FuncReturn(retval);
87 }
77} 88}
78 89
79template<ResultCode func(void*, void*, u32)> void Wrap(){ 90template<ResultCode func(void*, void*, u32)> void Wrap(){
diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp
index e45deb1c6..f338f3266 100644
--- a/src/core/hle/kernel/event.cpp
+++ b/src/core/hle/kernel/event.cpp
@@ -41,10 +41,7 @@ void Event::Acquire() {
41 41
42void Event::Signal() { 42void Event::Signal() {
43 signaled = true; 43 signaled = true;
44
45 WakeupAllWaitingThreads(); 44 WakeupAllWaitingThreads();
46
47 HLE::Reschedule(__func__);
48} 45}
49 46
50void Event::Clear() { 47void Event::Clear() {
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 726e4d2ff..20e11da16 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -32,27 +32,13 @@ void WaitObject::RemoveWaitingThread(Thread* thread) {
32 waiting_threads.erase(itr); 32 waiting_threads.erase(itr);
33} 33}
34 34
35SharedPtr<Thread> WaitObject::WakeupNextThread() {
36 if (waiting_threads.empty())
37 return nullptr;
38
39 auto next_thread = std::move(waiting_threads.front());
40 waiting_threads.erase(waiting_threads.begin());
41
42 next_thread->ReleaseWaitObject(this);
43
44 return next_thread;
45}
46
47void WaitObject::WakeupAllWaitingThreads() { 35void WaitObject::WakeupAllWaitingThreads() {
48 auto waiting_threads_copy = waiting_threads; 36 for (auto thread : waiting_threads)
37 thread->ResumeFromWait();
49 38
50 // We use a copy because ReleaseWaitObject will remove the thread from this object's 39 waiting_threads.clear();
51 // waiting_threads list
52 for (auto thread : waiting_threads_copy)
53 thread->ReleaseWaitObject(this);
54 40
55 ASSERT_MSG(waiting_threads.empty(), "failed to awaken all waiting threads!"); 41 HLE::Reschedule(__func__);
56} 42}
57 43
58HandleTable::HandleTable() { 44HandleTable::HandleTable() {
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index a5a0f4800..64595f758 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -140,12 +140,6 @@ public:
140 */ 140 */
141 void RemoveWaitingThread(Thread* thread); 141 void RemoveWaitingThread(Thread* thread);
142 142
143 /**
144 * Wake up the next thread waiting on this object
145 * @return Pointer to the thread that was resumed, nullptr if no threads are waiting
146 */
147 SharedPtr<Thread> WakeupNextThread();
148
149 /// Wake up all threads waiting on this object 143 /// Wake up all threads waiting on this object
150 void WakeupAllWaitingThreads(); 144 void WakeupAllWaitingThreads();
151 145
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index 6aa73df86..edb97d324 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -23,12 +23,7 @@ static void ResumeWaitingThread(Mutex* mutex) {
23 // Reset mutex lock thread handle, nothing is waiting 23 // Reset mutex lock thread handle, nothing is waiting
24 mutex->lock_count = 0; 24 mutex->lock_count = 0;
25 mutex->holding_thread = nullptr; 25 mutex->holding_thread = nullptr;
26 26 mutex->WakeupAllWaitingThreads();
27 // Find the next waiting thread for the mutex...
28 auto next_thread = mutex->WakeupNextThread();
29 if (next_thread != nullptr) {
30 mutex->Acquire(next_thread);
31 }
32} 27}
33 28
34void ReleaseThreadMutexes(Thread* thread) { 29void ReleaseThreadMutexes(Thread* thread) {
@@ -94,8 +89,6 @@ void Mutex::Release() {
94 ResumeWaitingThread(this); 89 ResumeWaitingThread(this);
95 } 90 }
96 } 91 }
97
98 HLE::Reschedule(__func__);
99} 92}
100 93
101} // namespace 94} // namespace
diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp
index 96d61ed3a..4b359ed07 100644
--- a/src/core/hle/kernel/semaphore.cpp
+++ b/src/core/hle/kernel/semaphore.cpp
@@ -48,13 +48,7 @@ ResultVal<s32> Semaphore::Release(s32 release_count) {
48 s32 previous_count = available_count; 48 s32 previous_count = available_count;
49 available_count += release_count; 49 available_count += release_count;
50 50
51 // Notify some of the threads that the semaphore has been released 51 WakeupAllWaitingThreads();
52 // stop once the semaphore is full again or there are no more waiting threads
53 while (!ShouldWait() && WakeupNextThread() != nullptr) {
54 Acquire();
55 }
56
57 HLE::Reschedule(__func__);
58 52
59 return MakeResult<s32>(previous_count); 53 return MakeResult<s32>(previous_count);
60} 54}
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 22c795ad4..4729a7fe0 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -13,6 +13,7 @@
13#include "common/thread_queue_list.h" 13#include "common/thread_queue_list.h"
14 14
15#include "core/arm/arm_interface.h" 15#include "core/arm/arm_interface.h"
16#include "core/arm/skyeye_common/armdefs.h"
16#include "core/core.h" 17#include "core/core.h"
17#include "core/core_timing.h" 18#include "core/core_timing.h"
18#include "core/hle/hle.h" 19#include "core/hle/hle.h"
@@ -193,8 +194,22 @@ static void SwitchContext(Thread* new_thread) {
193 if (new_thread) { 194 if (new_thread) {
194 DEBUG_ASSERT_MSG(new_thread->status == THREADSTATUS_READY, "Thread must be ready to become running."); 195 DEBUG_ASSERT_MSG(new_thread->status == THREADSTATUS_READY, "Thread must be ready to become running.");
195 196
197 // Cancel any outstanding wakeup events for this thread
198 CoreTiming::UnscheduleEvent(ThreadWakeupEventType, new_thread->callback_handle);
199
196 current_thread = new_thread; 200 current_thread = new_thread;
197 201
202 // If the thread was waited by a svcWaitSynch call, step back PC by one instruction to rerun
203 // the SVC when the thread wakes up. This is necessary to ensure that the thread can acquire
204 // the requested wait object(s) before continuing.
205 if (new_thread->waitsynch_waited) {
206 // CPSR flag indicates CPU mode
207 bool thumb_mode = (new_thread->context.cpsr & TBIT) != 0;
208
209 // SVC instruction is 2 bytes for THUMB, 4 bytes for ARM
210 new_thread->context.pc -= thumb_mode ? 2 : 4;
211 }
212
198 ready_queue.remove(new_thread->current_priority, new_thread); 213 ready_queue.remove(new_thread->current_priority, new_thread);
199 new_thread->status = THREADSTATUS_RUNNING; 214 new_thread->status = THREADSTATUS_RUNNING;
200 215
@@ -243,6 +258,7 @@ void WaitCurrentThread_WaitSynchronization(std::vector<SharedPtr<WaitObject>> wa
243 thread->wait_set_output = wait_set_output; 258 thread->wait_set_output = wait_set_output;
244 thread->wait_all = wait_all; 259 thread->wait_all = wait_all;
245 thread->wait_objects = std::move(wait_objects); 260 thread->wait_objects = std::move(wait_objects);
261 thread->waitsynch_waited = true;
246 thread->status = THREADSTATUS_WAIT_SYNCH; 262 thread->status = THREADSTATUS_WAIT_SYNCH;
247} 263}
248 264
@@ -268,6 +284,8 @@ static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) {
268 return; 284 return;
269 } 285 }
270 286
287 thread->waitsynch_waited = false;
288
271 if (thread->status == THREADSTATUS_WAIT_SYNCH) { 289 if (thread->status == THREADSTATUS_WAIT_SYNCH) {
272 thread->SetWaitSynchronizationResult(ResultCode(ErrorDescription::Timeout, ErrorModule::OS, 290 thread->SetWaitSynchronizationResult(ResultCode(ErrorDescription::Timeout, ErrorModule::OS,
273 ErrorSummary::StatusChanged, ErrorLevel::Info)); 291 ErrorSummary::StatusChanged, ErrorLevel::Info));
@@ -288,63 +306,20 @@ void Thread::WakeAfterDelay(s64 nanoseconds) {
288 CoreTiming::ScheduleEvent(usToCycles(microseconds), ThreadWakeupEventType, callback_handle); 306 CoreTiming::ScheduleEvent(usToCycles(microseconds), ThreadWakeupEventType, callback_handle);
289} 307}
290 308
291void Thread::ReleaseWaitObject(WaitObject* wait_object) {
292 if (status != THREADSTATUS_WAIT_SYNCH || wait_objects.empty()) {
293 LOG_CRITICAL(Kernel, "thread is not waiting on any objects!");
294 return;
295 }
296
297 // Remove this thread from the waiting object's thread list
298 wait_object->RemoveWaitingThread(this);
299
300 unsigned index = 0;
301 bool wait_all_failed = false; // Will be set to true if any object is unavailable
302
303 // Iterate through all waiting objects to check availability...
304 for (auto itr = wait_objects.begin(); itr != wait_objects.end(); ++itr) {
305 if ((*itr)->ShouldWait())
306 wait_all_failed = true;
307
308 // The output should be the last index of wait_object
309 if (*itr == wait_object)
310 index = itr - wait_objects.begin();
311 }
312
313 // If we are waiting on all objects...
314 if (wait_all) {
315 // Resume the thread only if all are available...
316 if (!wait_all_failed) {
317 SetWaitSynchronizationResult(RESULT_SUCCESS);
318 SetWaitSynchronizationOutput(-1);
319
320 ResumeFromWait();
321 }
322 } else {
323 // Otherwise, resume
324 SetWaitSynchronizationResult(RESULT_SUCCESS);
325
326 if (wait_set_output)
327 SetWaitSynchronizationOutput(index);
328
329 ResumeFromWait();
330 }
331}
332
333void Thread::ResumeFromWait() { 309void Thread::ResumeFromWait() {
334 // Cancel any outstanding wakeup events for this thread
335 CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle);
336
337 switch (status) { 310 switch (status) {
338 case THREADSTATUS_WAIT_SYNCH: 311 case THREADSTATUS_WAIT_SYNCH:
339 // Remove this thread from all other WaitObjects
340 for (auto wait_object : wait_objects)
341 wait_object->RemoveWaitingThread(this);
342 break;
343 case THREADSTATUS_WAIT_ARB: 312 case THREADSTATUS_WAIT_ARB:
344 case THREADSTATUS_WAIT_SLEEP: 313 case THREADSTATUS_WAIT_SLEEP:
345 break; 314 break;
346 case THREADSTATUS_RUNNING: 315
347 case THREADSTATUS_READY: 316 case THREADSTATUS_READY:
317 // If the thread is waiting on multiple wait objects, it might be awoken more than once
318 // before actually resuming. We can ignore subsequent wakeups if the thread status has
319 // already been set to THREADSTATUS_READY.
320 return;
321
322 case THREADSTATUS_RUNNING:
348 DEBUG_ASSERT_MSG(false, "Thread with object id %u has already resumed.", GetObjectId()); 323 DEBUG_ASSERT_MSG(false, "Thread with object id %u has already resumed.", GetObjectId());
349 return; 324 return;
350 case THREADSTATUS_DEAD: 325 case THREADSTATUS_DEAD:
@@ -415,6 +390,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
415 thread->callback_handle = wakeup_callback_handle_table.Create(thread).MoveFrom(); 390 thread->callback_handle = wakeup_callback_handle_table.Create(thread).MoveFrom();
416 thread->owner_process = g_current_process; 391 thread->owner_process = g_current_process;
417 thread->tls_index = -1; 392 thread->tls_index = -1;
393 thread->waitsynch_waited = false;
418 394
419 // Find the next available TLS index, and mark it as used 395 // Find the next available TLS index, and mark it as used
420 auto& used_tls_slots = Kernel::g_current_process->used_tls_slots; 396 auto& used_tls_slots = Kernel::g_current_process->used_tls_slots;
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 2c65419c3..b8160bb2c 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -96,12 +96,6 @@ public:
96 u32 GetThreadId() const { return thread_id; } 96 u32 GetThreadId() const { return thread_id; }
97 97
98 /** 98 /**
99 * Release an acquired wait object
100 * @param wait_object WaitObject to release
101 */
102 void ReleaseWaitObject(WaitObject* wait_object);
103
104 /**
105 * Resumes a thread from waiting 99 * Resumes a thread from waiting
106 */ 100 */
107 void ResumeFromWait(); 101 void ResumeFromWait();
@@ -152,6 +146,8 @@ public:
152 146
153 s32 tls_index; ///< Index of the Thread Local Storage of the thread 147 s32 tls_index; ///< Index of the Thread Local Storage of the thread
154 148
149 bool waitsynch_waited; ///< Set to true if the last svcWaitSynch call caused the thread to wait
150
155 /// Mutexes currently held by this thread, which will be released when it exits. 151 /// Mutexes currently held by this thread, which will be released when it exits.
156 boost::container::flat_set<SharedPtr<Mutex>> held_mutexes; 152 boost::container::flat_set<SharedPtr<Mutex>> held_mutexes;
157 153
@@ -163,12 +159,12 @@ public:
163 159
164 std::string name; 160 std::string name;
165 161
162 /// Handle used as userdata to reference this object when inserting into the CoreTiming queue.
163 Handle callback_handle;
164
166private: 165private:
167 Thread(); 166 Thread();
168 ~Thread() override; 167 ~Thread() override;
169
170 /// Handle used as userdata to reference this object when inserting into the CoreTiming queue.
171 Handle callback_handle;
172}; 168};
173 169
174/** 170/**
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index d1555c753..6cde4fc87 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -40,9 +40,6 @@ const ResultCode ERR_NOT_FOUND(ErrorDescription::NotFound, ErrorModule::Kernel,
40const ResultCode ERR_PORT_NAME_TOO_LONG(ErrorDescription(30), ErrorModule::OS, 40const ResultCode ERR_PORT_NAME_TOO_LONG(ErrorDescription(30), ErrorModule::OS,
41 ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E0181E 41 ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E0181E
42 42
43/// An invalid result code that is meant to be overwritten when a thread resumes from waiting
44const ResultCode RESULT_INVALID(0xDEADC0DE);
45
46enum ControlMemoryOperation { 43enum ControlMemoryOperation {
47 MEMORY_OPERATION_HEAP = 0x00000003, 44 MEMORY_OPERATION_HEAP = 0x00000003,
48 MEMORY_OPERATION_GSP_HEAP = 0x00010003, 45 MEMORY_OPERATION_GSP_HEAP = 0x00010003,
@@ -143,6 +140,10 @@ static ResultCode CloseHandle(Handle handle) {
143/// Wait for a handle to synchronize, timeout after the specified nanoseconds 140/// Wait for a handle to synchronize, timeout after the specified nanoseconds
144static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) { 141static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) {
145 auto object = Kernel::g_handle_table.GetWaitObject(handle); 142 auto object = Kernel::g_handle_table.GetWaitObject(handle);
143 Kernel::Thread* thread = Kernel::GetCurrentThread();
144
145 thread->waitsynch_waited = false;
146
146 if (object == nullptr) 147 if (object == nullptr)
147 return ERR_INVALID_HANDLE; 148 return ERR_INVALID_HANDLE;
148 149
@@ -154,14 +155,14 @@ static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) {
154 // Check for next thread to schedule 155 // Check for next thread to schedule
155 if (object->ShouldWait()) { 156 if (object->ShouldWait()) {
156 157
157 object->AddWaitingThread(Kernel::GetCurrentThread()); 158 object->AddWaitingThread(thread);
158 Kernel::WaitCurrentThread_WaitSynchronization({ object }, false, false); 159 Kernel::WaitCurrentThread_WaitSynchronization({ object }, false, false);
159 160
160 // Create an event to wake the thread up after the specified nanosecond delay has passed 161 // Create an event to wake the thread up after the specified nanosecond delay has passed
161 Kernel::GetCurrentThread()->WakeAfterDelay(nano_seconds); 162 thread->WakeAfterDelay(nano_seconds);
162 163
163 // NOTE: output of this SVC will be set later depending on how the thread resumes 164 // NOTE: output of this SVC will be set later depending on how the thread resumes
164 return RESULT_INVALID; 165 return HLE::RESULT_INVALID;
165 } 166 }
166 167
167 object->Acquire(); 168 object->Acquire();
@@ -173,6 +174,9 @@ static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) {
173static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all, s64 nano_seconds) { 174static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all, s64 nano_seconds) {
174 bool wait_thread = !wait_all; 175 bool wait_thread = !wait_all;
175 int handle_index = 0; 176 int handle_index = 0;
177 Kernel::Thread* thread = Kernel::GetCurrentThread();
178 bool was_waiting = thread->waitsynch_waited;
179 thread->waitsynch_waited = false;
176 180
177 // Check if 'handles' is invalid 181 // Check if 'handles' is invalid
178 if (handles == nullptr) 182 if (handles == nullptr)
@@ -190,6 +194,9 @@ static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_cou
190 // necessary 194 // necessary
191 if (handle_count != 0) { 195 if (handle_count != 0) {
192 bool selected = false; // True once an object has been selected 196 bool selected = false; // True once an object has been selected
197
198 Kernel::SharedPtr<Kernel::WaitObject> wait_object;
199
193 for (int i = 0; i < handle_count; ++i) { 200 for (int i = 0; i < handle_count; ++i) {
194 auto object = Kernel::g_handle_table.GetWaitObject(handles[i]); 201 auto object = Kernel::g_handle_table.GetWaitObject(handles[i]);
195 if (object == nullptr) 202 if (object == nullptr)
@@ -204,10 +211,11 @@ static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_cou
204 wait_thread = true; 211 wait_thread = true;
205 } else { 212 } else {
206 // Do not wait on this object, check if this object should be selected... 213 // Do not wait on this object, check if this object should be selected...
207 if (!wait_all && !selected) { 214 if (!wait_all && (!selected || (wait_object == object && was_waiting))) {
208 // Do not wait the thread 215 // Do not wait the thread
209 wait_thread = false; 216 wait_thread = false;
210 handle_index = i; 217 handle_index = i;
218 wait_object = object;
211 selected = true; 219 selected = true;
212 } 220 }
213 } 221 }
@@ -241,7 +249,7 @@ static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_cou
241 Kernel::GetCurrentThread()->WakeAfterDelay(nano_seconds); 249 Kernel::GetCurrentThread()->WakeAfterDelay(nano_seconds);
242 250
243 // NOTE: output of this SVC will be set later depending on how the thread resumes 251 // NOTE: output of this SVC will be set later depending on how the thread resumes
244 return RESULT_INVALID; 252 return HLE::RESULT_INVALID;
245 } 253 }
246 254
247 // Acquire objects if we did not wait... 255 // Acquire objects if we did not wait...
@@ -261,7 +269,7 @@ static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_cou
261 269
262 // TODO(bunnei): If 'wait_all' is true, this is probably wrong. However, real hardware does 270 // TODO(bunnei): If 'wait_all' is true, this is probably wrong. However, real hardware does
263 // not seem to set it to any meaningful value. 271 // not seem to set it to any meaningful value.
264 *out = wait_all ? 0 : handle_index; 272 *out = handle_count != 0 ? (wait_all ? -1 : handle_index) : 0;
265 273
266 return RESULT_SUCCESS; 274 return RESULT_SUCCESS;
267} 275}
diff --git a/src/core/hw/hw.cpp b/src/core/hw/hw.cpp
index f4906cc7e..c7006a498 100644
--- a/src/core/hw/hw.cpp
+++ b/src/core/hw/hw.cpp
@@ -18,7 +18,7 @@ inline void Read(T &var, const u32 addr) {
18 GPU::Read(var, addr); 18 GPU::Read(var, addr);
19 break; 19 break;
20 case VADDR_LCD: 20 case VADDR_LCD:
21 LCD::Write(var, addr); 21 LCD::Read(var, addr);
22 break; 22 break;
23 default: 23 default:
24 LOG_ERROR(HW_Memory, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, addr); 24 LOG_ERROR(HW_Memory, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, addr);
diff --git a/src/video_core/pica.h b/src/video_core/pica.h
index 684ec9818..9628a7589 100644
--- a/src/video_core/pica.h
+++ b/src/video_core/pica.h
@@ -372,9 +372,9 @@ struct Regs {
372 INSERT_PADDING_WORDS(0x2); 372 INSERT_PADDING_WORDS(0x2);
373 373
374 const std::array<Regs::TevStageConfig,6> GetTevStages() const { 374 const std::array<Regs::TevStageConfig,6> GetTevStages() const {
375 return { tev_stage0, tev_stage1, 375 return {{ tev_stage0, tev_stage1,
376 tev_stage2, tev_stage3, 376 tev_stage2, tev_stage3,
377 tev_stage4, tev_stage5 }; 377 tev_stage4, tev_stage5 }};
378 }; 378 };
379 379
380 enum class BlendEquation : u32 { 380 enum class BlendEquation : u32 {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index d31c46cca..518f79331 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -94,14 +94,27 @@ void RasterizerOpenGL::InitObjects() {
94 // Create textures for OGL framebuffer that will be rendered to, initially 1x1 to succeed in framebuffer creation 94 // Create textures for OGL framebuffer that will be rendered to, initially 1x1 to succeed in framebuffer creation
95 fb_color_texture.texture.Create(); 95 fb_color_texture.texture.Create();
96 ReconfigureColorTexture(fb_color_texture, Pica::Regs::ColorFormat::RGBA8, 1, 1); 96 ReconfigureColorTexture(fb_color_texture, Pica::Regs::ColorFormat::RGBA8, 1, 1);
97
98 state.texture_units[0].enabled_2d = true;
99 state.texture_units[0].texture_2d = fb_color_texture.texture.handle;
100 state.Apply();
101
97 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); 102 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
98 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 103 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
99 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 104 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
100 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 105 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
101 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 106 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
102 107
108 state.texture_units[0].texture_2d = 0;
109 state.Apply();
110
103 fb_depth_texture.texture.Create(); 111 fb_depth_texture.texture.Create();
104 ReconfigureDepthTexture(fb_depth_texture, Pica::Regs::DepthFormat::D16, 1, 1); 112 ReconfigureDepthTexture(fb_depth_texture, Pica::Regs::DepthFormat::D16, 1, 1);
113
114 state.texture_units[0].enabled_2d = true;
115 state.texture_units[0].texture_2d = fb_depth_texture.texture.handle;
116 state.Apply();
117
105 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); 118 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
106 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 119 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
107 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 120 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
@@ -110,14 +123,13 @@ void RasterizerOpenGL::InitObjects() {
110 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); 123 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
111 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); 124 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
112 125
126 state.texture_units[0].texture_2d = 0;
127 state.Apply();
128
113 // Configure OpenGL framebuffer 129 // Configure OpenGL framebuffer
114 framebuffer.Create(); 130 framebuffer.Create();
115 131
116 state.draw.framebuffer = framebuffer.handle; 132 state.draw.framebuffer = framebuffer.handle;
117
118 // Unbind texture to allow binding to framebuffer
119 state.texture_units[0].enabled_2d = true;
120 state.texture_units[0].texture_2d = 0;
121 state.Apply(); 133 state.Apply();
122 134
123 glActiveTexture(GL_TEXTURE0); 135 glActiveTexture(GL_TEXTURE0);
@@ -205,7 +217,19 @@ void RasterizerOpenGL::DrawTriangles() {
205 217
206 vertex_batch.clear(); 218 vertex_batch.clear();
207 219
208 // TODO: Flush the resource cache at the current depth and color framebuffer addresses for render-to-texture 220 // Flush the resource cache at the current depth and color framebuffer addresses for render-to-texture
221 const auto& regs = Pica::g_state.regs;
222
223 PAddr cur_fb_color_addr = regs.framebuffer.GetColorBufferPhysicalAddress();
224 u32 cur_fb_color_size = Pica::Regs::BytesPerColorPixel(regs.framebuffer.color_format)
225 * regs.framebuffer.GetWidth() * regs.framebuffer.GetHeight();
226
227 PAddr cur_fb_depth_addr = regs.framebuffer.GetDepthBufferPhysicalAddress();
228 u32 cur_fb_depth_size = Pica::Regs::BytesPerDepthPixel(regs.framebuffer.depth_format)
229 * regs.framebuffer.GetWidth() * regs.framebuffer.GetHeight();
230
231 res_cache.NotifyFlush(cur_fb_color_addr, cur_fb_color_size);
232 res_cache.NotifyFlush(cur_fb_depth_addr, cur_fb_depth_size);
209} 233}
210 234
211void RasterizerOpenGL::CommitFramebuffer() { 235void RasterizerOpenGL::CommitFramebuffer() {
@@ -472,6 +496,9 @@ void RasterizerOpenGL::ReconfigureColorTexture(TextureInfo& texture, Pica::Regs:
472 glActiveTexture(GL_TEXTURE0); 496 glActiveTexture(GL_TEXTURE0);
473 glTexImage2D(GL_TEXTURE_2D, 0, internal_format, texture.width, texture.height, 0, 497 glTexImage2D(GL_TEXTURE_2D, 0, internal_format, texture.width, texture.height, 0,
474 texture.gl_format, texture.gl_type, nullptr); 498 texture.gl_format, texture.gl_type, nullptr);
499
500 state.texture_units[0].texture_2d = 0;
501 state.Apply();
475} 502}
476 503
477void RasterizerOpenGL::ReconfigureDepthTexture(DepthTextureInfo& texture, Pica::Regs::DepthFormat format, u32 width, u32 height) { 504void RasterizerOpenGL::ReconfigureDepthTexture(DepthTextureInfo& texture, Pica::Regs::DepthFormat format, u32 width, u32 height) {
@@ -491,7 +518,7 @@ void RasterizerOpenGL::ReconfigureDepthTexture(DepthTextureInfo& texture, Pica::
491 case Pica::Regs::DepthFormat::D24: 518 case Pica::Regs::DepthFormat::D24:
492 internal_format = GL_DEPTH_COMPONENT24; 519 internal_format = GL_DEPTH_COMPONENT24;
493 texture.gl_format = GL_DEPTH_COMPONENT; 520 texture.gl_format = GL_DEPTH_COMPONENT;
494 texture.gl_type = GL_UNSIGNED_INT_24_8; 521 texture.gl_type = GL_UNSIGNED_INT;
495 break; 522 break;
496 523
497 case Pica::Regs::DepthFormat::D24S8: 524 case Pica::Regs::DepthFormat::D24S8:
@@ -513,6 +540,9 @@ void RasterizerOpenGL::ReconfigureDepthTexture(DepthTextureInfo& texture, Pica::
513 glActiveTexture(GL_TEXTURE0); 540 glActiveTexture(GL_TEXTURE0);
514 glTexImage2D(GL_TEXTURE_2D, 0, internal_format, texture.width, texture.height, 0, 541 glTexImage2D(GL_TEXTURE_2D, 0, internal_format, texture.width, texture.height, 0,
515 texture.gl_format, texture.gl_type, nullptr); 542 texture.gl_format, texture.gl_type, nullptr);
543
544 state.texture_units[0].texture_2d = 0;
545 state.Apply();
516} 546}
517 547
518void RasterizerOpenGL::SyncFramebuffer() { 548void RasterizerOpenGL::SyncFramebuffer() {
@@ -652,6 +682,10 @@ void RasterizerOpenGL::SyncDepthTest() {
652 const auto& regs = Pica::g_state.regs; 682 const auto& regs = Pica::g_state.regs;
653 state.depth.test_enabled = (regs.output_merger.depth_test_enable == 1); 683 state.depth.test_enabled = (regs.output_merger.depth_test_enable == 1);
654 state.depth.test_func = PicaToGL::CompareFunc(regs.output_merger.depth_test_func); 684 state.depth.test_func = PicaToGL::CompareFunc(regs.output_merger.depth_test_func);
685 state.color_mask.red_enabled = regs.output_merger.red_enable;
686 state.color_mask.green_enabled = regs.output_merger.green_enable;
687 state.color_mask.blue_enabled = regs.output_merger.blue_enable;
688 state.color_mask.alpha_enabled = regs.output_merger.alpha_enable;
655 state.depth.write_mask = regs.output_merger.depth_write_enable ? GL_TRUE : GL_FALSE; 689 state.depth.write_mask = regs.output_merger.depth_write_enable ? GL_TRUE : GL_FALSE;
656} 690}
657 691
@@ -759,10 +793,10 @@ void RasterizerOpenGL::ReloadColorBuffer() {
759 for (int x = 0; x < fb_color_texture.width; ++x) { 793 for (int x = 0; x < fb_color_texture.width; ++x) {
760 const u32 coarse_y = y & ~7; 794 const u32 coarse_y = y & ~7;
761 u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_color_texture.width * bytes_per_pixel; 795 u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_color_texture.width * bytes_per_pixel;
762 u32 gl_px_idx = x * bytes_per_pixel + y * fb_color_texture.width * bytes_per_pixel; 796 u32 gl_pixel_index = (x + y * fb_color_texture.width) * bytes_per_pixel;
763 797
764 u8* pixel = color_buffer + dst_offset; 798 u8* pixel = color_buffer + dst_offset;
765 memcpy(&temp_fb_color_buffer[gl_px_idx], pixel, bytes_per_pixel); 799 memcpy(&temp_fb_color_buffer[gl_pixel_index], pixel, bytes_per_pixel);
766 } 800 }
767 } 801 }
768 802
@@ -773,6 +807,9 @@ void RasterizerOpenGL::ReloadColorBuffer() {
773 glActiveTexture(GL_TEXTURE0); 807 glActiveTexture(GL_TEXTURE0);
774 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, fb_color_texture.width, fb_color_texture.height, 808 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, fb_color_texture.width, fb_color_texture.height,
775 fb_color_texture.gl_format, fb_color_texture.gl_type, temp_fb_color_buffer.get()); 809 fb_color_texture.gl_format, fb_color_texture.gl_type, temp_fb_color_buffer.get());
810
811 state.texture_units[0].texture_2d = 0;
812 state.Apply();
776} 813}
777 814
778void RasterizerOpenGL::ReloadDepthBuffer() { 815void RasterizerOpenGL::ReloadDepthBuffer() {
@@ -790,29 +827,29 @@ void RasterizerOpenGL::ReloadDepthBuffer() {
790 827
791 std::unique_ptr<u8[]> temp_fb_depth_buffer(new u8[fb_depth_texture.width * fb_depth_texture.height * gl_bpp]); 828 std::unique_ptr<u8[]> temp_fb_depth_buffer(new u8[fb_depth_texture.width * fb_depth_texture.height * gl_bpp]);
792 829
793 for (int y = 0; y < fb_depth_texture.height; ++y) { 830 u8* temp_fb_depth_data = bytes_per_pixel == 3 ? (temp_fb_depth_buffer.get() + 1) : temp_fb_depth_buffer.get();
794 for (int x = 0; x < fb_depth_texture.width; ++x) { 831
795 const u32 coarse_y = y & ~7; 832 if (fb_depth_texture.format == Pica::Regs::DepthFormat::D24S8) {
796 u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_depth_texture.width * bytes_per_pixel; 833 for (int y = 0; y < fb_depth_texture.height; ++y) {
797 u32 gl_px_idx = x + y * fb_depth_texture.width; 834 for (int x = 0; x < fb_depth_texture.width; ++x) {
798 835 const u32 coarse_y = y & ~7;
799 switch (fb_depth_texture.format) { 836 u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_depth_texture.width * bytes_per_pixel;
800 case Pica::Regs::DepthFormat::D16: 837 u32 gl_pixel_index = (x + y * fb_depth_texture.width);
801 ((u16*)temp_fb_depth_buffer.get())[gl_px_idx] = Color::DecodeD16(depth_buffer + dst_offset); 838
802 break; 839 u8* pixel = depth_buffer + dst_offset;
803 case Pica::Regs::DepthFormat::D24: 840 u32 depth_stencil = *(u32*)pixel;
804 ((u32*)temp_fb_depth_buffer.get())[gl_px_idx] = Color::DecodeD24(depth_buffer + dst_offset); 841 ((u32*)temp_fb_depth_data)[gl_pixel_index] = (depth_stencil << 8) | (depth_stencil >> 24);
805 break;
806 case Pica::Regs::DepthFormat::D24S8:
807 {
808 Math::Vec2<u32> depth_stencil = Color::DecodeD24S8(depth_buffer + dst_offset);
809 ((u32*)temp_fb_depth_buffer.get())[gl_px_idx] = (depth_stencil.x << 8) | depth_stencil.y;
810 break;
811 } 842 }
812 default: 843 }
813 LOG_CRITICAL(Render_OpenGL, "Unknown memory framebuffer depth format %x", fb_depth_texture.format); 844 } else {
814 UNIMPLEMENTED(); 845 for (int y = 0; y < fb_depth_texture.height; ++y) {
815 break; 846 for (int x = 0; x < fb_depth_texture.width; ++x) {
847 const u32 coarse_y = y & ~7;
848 u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_depth_texture.width * bytes_per_pixel;
849 u32 gl_pixel_index = (x + y * fb_depth_texture.width) * gl_bpp;
850
851 u8* pixel = depth_buffer + dst_offset;
852 memcpy(&temp_fb_depth_data[gl_pixel_index], pixel, bytes_per_pixel);
816 } 853 }
817 } 854 }
818 } 855 }
@@ -824,6 +861,9 @@ void RasterizerOpenGL::ReloadDepthBuffer() {
824 glActiveTexture(GL_TEXTURE0); 861 glActiveTexture(GL_TEXTURE0);
825 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, fb_depth_texture.width, fb_depth_texture.height, 862 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, fb_depth_texture.width, fb_depth_texture.height,
826 fb_depth_texture.gl_format, fb_depth_texture.gl_type, temp_fb_depth_buffer.get()); 863 fb_depth_texture.gl_format, fb_depth_texture.gl_type, temp_fb_depth_buffer.get());
864
865 state.texture_units[0].texture_2d = 0;
866 state.Apply();
827} 867}
828 868
829void RasterizerOpenGL::CommitColorBuffer() { 869void RasterizerOpenGL::CommitColorBuffer() {
@@ -842,15 +882,18 @@ void RasterizerOpenGL::CommitColorBuffer() {
842 glActiveTexture(GL_TEXTURE0); 882 glActiveTexture(GL_TEXTURE0);
843 glGetTexImage(GL_TEXTURE_2D, 0, fb_color_texture.gl_format, fb_color_texture.gl_type, temp_gl_color_buffer.get()); 883 glGetTexImage(GL_TEXTURE_2D, 0, fb_color_texture.gl_format, fb_color_texture.gl_type, temp_gl_color_buffer.get());
844 884
885 state.texture_units[0].texture_2d = 0;
886 state.Apply();
887
845 // Directly copy pixels. Internal OpenGL color formats are consistent so no conversion is necessary. 888 // Directly copy pixels. Internal OpenGL color formats are consistent so no conversion is necessary.
846 for (int y = 0; y < fb_color_texture.height; ++y) { 889 for (int y = 0; y < fb_color_texture.height; ++y) {
847 for (int x = 0; x < fb_color_texture.width; ++x) { 890 for (int x = 0; x < fb_color_texture.width; ++x) {
848 const u32 coarse_y = y & ~7; 891 const u32 coarse_y = y & ~7;
849 u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_color_texture.width * bytes_per_pixel; 892 u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_color_texture.width * bytes_per_pixel;
850 u32 gl_px_idx = x * bytes_per_pixel + y * fb_color_texture.width * bytes_per_pixel; 893 u32 gl_pixel_index = x * bytes_per_pixel + y * fb_color_texture.width * bytes_per_pixel;
851 894
852 u8* pixel = color_buffer + dst_offset; 895 u8* pixel = color_buffer + dst_offset;
853 memcpy(pixel, &temp_gl_color_buffer[gl_px_idx], bytes_per_pixel); 896 memcpy(pixel, &temp_gl_color_buffer[gl_pixel_index], bytes_per_pixel);
854 } 897 }
855 } 898 }
856 } 899 }
@@ -877,29 +920,32 @@ void RasterizerOpenGL::CommitDepthBuffer() {
877 glActiveTexture(GL_TEXTURE0); 920 glActiveTexture(GL_TEXTURE0);
878 glGetTexImage(GL_TEXTURE_2D, 0, fb_depth_texture.gl_format, fb_depth_texture.gl_type, temp_gl_depth_buffer.get()); 921 glGetTexImage(GL_TEXTURE_2D, 0, fb_depth_texture.gl_format, fb_depth_texture.gl_type, temp_gl_depth_buffer.get());
879 922
880 for (int y = 0; y < fb_depth_texture.height; ++y) { 923 state.texture_units[0].texture_2d = 0;
881 for (int x = 0; x < fb_depth_texture.width; ++x) { 924 state.Apply();
882 const u32 coarse_y = y & ~7; 925
883 u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_depth_texture.width * bytes_per_pixel; 926 u8* temp_gl_depth_data = bytes_per_pixel == 3 ? (temp_gl_depth_buffer.get() + 1) : temp_gl_depth_buffer.get();
884 u32 gl_px_idx = x + y * fb_depth_texture.width; 927
885 928 if (fb_depth_texture.format == Pica::Regs::DepthFormat::D24S8) {
886 switch (fb_depth_texture.format) { 929 for (int y = 0; y < fb_depth_texture.height; ++y) {
887 case Pica::Regs::DepthFormat::D16: 930 for (int x = 0; x < fb_depth_texture.width; ++x) {
888 Color::EncodeD16(((u16*)temp_gl_depth_buffer.get())[gl_px_idx], depth_buffer + dst_offset); 931 const u32 coarse_y = y & ~7;
889 break; 932 u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_depth_texture.width * bytes_per_pixel;
890 case Pica::Regs::DepthFormat::D24: 933 u32 gl_pixel_index = (x + y * fb_depth_texture.width);
891 Color::EncodeD24(((u32*)temp_gl_depth_buffer.get())[gl_px_idx], depth_buffer + dst_offset); 934
892 break; 935 u8* pixel = depth_buffer + dst_offset;
893 case Pica::Regs::DepthFormat::D24S8: 936 u32 depth_stencil = ((u32*)temp_gl_depth_data)[gl_pixel_index];
894 { 937 *(u32*)pixel = (depth_stencil >> 8) | (depth_stencil << 24);
895 u32 depth_stencil = ((u32*)temp_gl_depth_buffer.get())[gl_px_idx];
896 Color::EncodeD24S8((depth_stencil >> 8), depth_stencil & 0xFF, depth_buffer + dst_offset);
897 break;
898 } 938 }
899 default: 939 }
900 LOG_CRITICAL(Render_OpenGL, "Unknown framebuffer depth format %x", fb_depth_texture.format); 940 } else {
901 UNIMPLEMENTED(); 941 for (int y = 0; y < fb_depth_texture.height; ++y) {
902 break; 942 for (int x = 0; x < fb_depth_texture.width; ++x) {
943 const u32 coarse_y = y & ~7;
944 u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_depth_texture.width * bytes_per_pixel;
945 u32 gl_pixel_index = (x + y * fb_depth_texture.width) * gl_bpp;
946
947 u8* pixel = depth_buffer + dst_offset;
948 memcpy(pixel, &temp_gl_depth_data[gl_pixel_index], bytes_per_pixel);
903 } 949 }
904 } 950 }
905 } 951 }
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index 9c5f38f94..3526e16d5 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -16,6 +16,11 @@ OpenGLState::OpenGLState() {
16 depth.test_func = GL_LESS; 16 depth.test_func = GL_LESS;
17 depth.write_mask = GL_TRUE; 17 depth.write_mask = GL_TRUE;
18 18
19 color_mask.red_enabled = GL_TRUE;
20 color_mask.green_enabled = GL_TRUE;
21 color_mask.blue_enabled = GL_TRUE;
22 color_mask.alpha_enabled = GL_TRUE;
23
19 stencil.test_enabled = false; 24 stencil.test_enabled = false;
20 stencil.test_func = GL_ALWAYS; 25 stencil.test_func = GL_ALWAYS;
21 stencil.test_ref = 0; 26 stencil.test_ref = 0;
@@ -77,6 +82,15 @@ void OpenGLState::Apply() {
77 glDepthMask(depth.write_mask); 82 glDepthMask(depth.write_mask);
78 } 83 }
79 84
85 // Color mask
86 if (color_mask.red_enabled != cur_state.color_mask.red_enabled ||
87 color_mask.green_enabled != cur_state.color_mask.green_enabled ||
88 color_mask.blue_enabled != cur_state.color_mask.blue_enabled ||
89 color_mask.alpha_enabled != cur_state.color_mask.alpha_enabled) {
90 glColorMask(color_mask.red_enabled, color_mask.green_enabled,
91 color_mask.blue_enabled, color_mask.alpha_enabled);
92 }
93
80 // Stencil test 94 // Stencil test
81 if (stencil.test_enabled != cur_state.stencil.test_enabled) { 95 if (stencil.test_enabled != cur_state.stencil.test_enabled) {
82 if (stencil.test_enabled) { 96 if (stencil.test_enabled) {
@@ -87,8 +101,8 @@ void OpenGLState::Apply() {
87 } 101 }
88 102
89 if (stencil.test_func != cur_state.stencil.test_func || 103 if (stencil.test_func != cur_state.stencil.test_func ||
90 stencil.test_ref != cur_state.stencil.test_ref || 104 stencil.test_ref != cur_state.stencil.test_ref ||
91 stencil.test_mask != cur_state.stencil.test_mask) { 105 stencil.test_mask != cur_state.stencil.test_mask) {
92 glStencilFunc(stencil.test_func, stencil.test_ref, stencil.test_mask); 106 glStencilFunc(stencil.test_func, stencil.test_ref, stencil.test_mask);
93 } 107 }
94 108
@@ -112,17 +126,19 @@ void OpenGLState::Apply() {
112 } 126 }
113 127
114 if (blend.color.red != cur_state.blend.color.red || 128 if (blend.color.red != cur_state.blend.color.red ||
115 blend.color.green != cur_state.blend.color.green || 129 blend.color.green != cur_state.blend.color.green ||
116 blend.color.blue != cur_state.blend.color.blue || 130 blend.color.blue != cur_state.blend.color.blue ||
117 blend.color.alpha != cur_state.blend.color.alpha) { 131 blend.color.alpha != cur_state.blend.color.alpha) {
118 glBlendColor(blend.color.red, blend.color.green, blend.color.blue, blend.color.alpha); 132 glBlendColor(blend.color.red, blend.color.green,
133 blend.color.blue, blend.color.alpha);
119 } 134 }
120 135
121 if (blend.src_rgb_func != cur_state.blend.src_rgb_func || 136 if (blend.src_rgb_func != cur_state.blend.src_rgb_func ||
122 blend.dst_rgb_func != cur_state.blend.dst_rgb_func || 137 blend.dst_rgb_func != cur_state.blend.dst_rgb_func ||
123 blend.src_a_func != cur_state.blend.src_a_func || 138 blend.src_a_func != cur_state.blend.src_a_func ||
124 blend.dst_a_func != cur_state.blend.dst_a_func) { 139 blend.dst_a_func != cur_state.blend.dst_a_func) {
125 glBlendFuncSeparate(blend.src_rgb_func, blend.dst_rgb_func, blend.src_a_func, blend.dst_a_func); 140 glBlendFuncSeparate(blend.src_rgb_func, blend.dst_rgb_func,
141 blend.src_a_func, blend.dst_a_func);
126 } 142 }
127 143
128 if (logic_op != cur_state.logic_op) { 144 if (logic_op != cur_state.logic_op) {
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index 6b97721d6..26b916360 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -20,6 +20,13 @@ public:
20 } depth; 20 } depth;
21 21
22 struct { 22 struct {
23 GLboolean red_enabled;
24 GLboolean green_enabled;
25 GLboolean blue_enabled;
26 GLboolean alpha_enabled;
27 } color_mask; // GL_COLOR_WRITEMASK
28
29 struct {
23 bool test_enabled; // GL_STENCIL_TEST 30 bool test_enabled; // GL_STENCIL_TEST
24 GLenum test_func; // GL_STENCIL_FUNC 31 GLenum test_func; // GL_STENCIL_FUNC
25 GLint test_ref; // GL_STENCIL_REF 32 GLint test_ref; // GL_STENCIL_REF
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 382aeaa05..3399ca123 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -170,6 +170,9 @@ void RendererOpenGL::LoadFBToActiveGLTexture(const GPU::Regs::FramebufferConfig&
170 texture.gl_format, texture.gl_type, framebuffer_data); 170 texture.gl_format, texture.gl_type, framebuffer_data);
171 171
172 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); 172 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
173
174 state.texture_units[0].texture_2d = 0;
175 state.Apply();
173} 176}
174 177
175/** 178/**
@@ -239,6 +242,9 @@ void RendererOpenGL::InitOpenGLObjects() {
239 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 242 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
240 } 243 }
241 244
245 state.texture_units[0].texture_2d = 0;
246 state.Apply();
247
242 hw_rasterizer->InitObjects(); 248 hw_rasterizer->InitObjects();
243} 249}
244 250
@@ -370,6 +376,8 @@ void RendererOpenGL::Init() {
370 } 376 }
371 377
372 LOG_INFO(Render_OpenGL, "GL_VERSION: %s", glGetString(GL_VERSION)); 378 LOG_INFO(Render_OpenGL, "GL_VERSION: %s", glGetString(GL_VERSION));
379 LOG_INFO(Render_OpenGL, "GL_VENDOR: %s", glGetString(GL_VENDOR));
380 LOG_INFO(Render_OpenGL, "GL_RENDERER: %s", glGetString(GL_RENDERER));
373 InitOpenGLObjects(); 381 InitOpenGLObjects();
374} 382}
375 383