My Project
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules
gsp.c
Go to the documentation of this file.
1 /*
2  gsp.c _ Gpu/lcd stuff.
3 */
4 
5 #include <stdlib.h>
6 #include <string.h>
7 #include <3ds.h>
8 
9 #define GSP_EVENT_STACK_SIZE 0x1000
10 
13 u64 gspEventStack[GSP_EVENT_STACK_SIZE/sizeof(u64)]; //u64 so that it's 8-byte aligned
14 volatile bool gspRunEvents;
16 
17 static Handle gspEvent;
18 static vu8* gspEventData;
19 
20 static void gspEventThreadMain(u32 arg);
21 
22 
24 {
25  return srvGetServiceHandle(&gspGpuHandle, "gsp::Gpu");
26 }
27 
28 void gspExit()
29 {
31 }
32 
33 Result gspInitEventHandler(Handle _gspEvent, vu8* _gspSharedMem, u8 gspThreadId)
34 {
35  // Create events
36  int i;
37  for (i = 0; i < GSPEVENT_MAX; i ++)
38  {
39  Result rc = svcCreateEvent(&gspEvents[i], 0);
40  if (rc != 0)
41  {
42  // Destroy already created events due to failure
43  int j;
44  for (j = 0; j < i; j ++)
46  return rc;
47  }
48  }
49 
50  // Start event thread
51  gspEvent = _gspEvent;
52  gspEventData = _gspSharedMem + gspThreadId*0x40;
53  gspRunEvents = true;
54  return svcCreateThread(&gspEventThread, gspEventThreadMain, 0x0, (u32*)((char*)gspEventStack + sizeof(gspEventStack)), 0x31, 0xfffffffe);
55 }
56 
58 {
59  // Stop event thread
60  gspRunEvents = false;
63 
64  // Free events
65  int i;
66  for (i = 0; i < GSPEVENT_MAX; i ++)
68 }
69 
70 void gspWaitForEvent(GSP_Event id, bool nextEvent)
71 {
72  if(id>=GSPEVENT_MAX)return;
73 
74  if (nextEvent)
77  if (!nextEvent)
79 }
80 
81 void gspEventThreadMain(u32 arg)
82 {
83  while (gspRunEvents)
84  {
87 
88  int count = gspEventData[1];
89  int cur = gspEventData[0];
90  int last = cur + count;
91  while (last >= 0x34) last -= 0x34;
92  int i;
93  for (i = 0; i < count; i ++)
94  {
95  int curEvt = gspEventData[0xC + cur];
96  cur ++;
97  if (cur >= 0x34) cur -= 0x34;
98  if (curEvt >= GSPEVENT_MAX) continue;
99  svcSignalEvent(gspEvents[curEvt]);
100  }
101 
102  gspEventData[0] = last;
103  gspEventData[1] -= count;
104  gspEventData[2] = 0;
105  }
106  svcExitThread();
107 }
108 
109 Result GSPGPU_WriteHWRegs(Handle* handle, u32 regAddr, u32* data, u8 size)
110 {
111  if(!handle)handle=&gspGpuHandle;
112 
113  if(size>0x80 || !data)return -1;
114 
115  u32* cmdbuf=getThreadCommandBuffer();
116  cmdbuf[0]=0x00010082; //request header code
117  cmdbuf[1]=regAddr;
118  cmdbuf[2]=size;
119  cmdbuf[3]=(size<<14)|2;
120  cmdbuf[4]=(u32)data;
121 
122  Result ret=0;
123  if((ret=svcSendSyncRequest(*handle)))return ret;
124 
125  return cmdbuf[1];
126 }
127 
128 Result GSPGPU_WriteHWRegsWithMask(Handle* handle, u32 regAddr, u32* data, u8 datasize, u32* maskdata, u8 masksize)
129 {
130  if(!handle)handle=&gspGpuHandle;
131 
132  if(datasize>0x80 || !data)return -1;
133 
134  u32* cmdbuf=getThreadCommandBuffer();
135  cmdbuf[0]=0x00020084; //request header code
136  cmdbuf[1]=regAddr;
137  cmdbuf[2]=datasize;
138  cmdbuf[3]=(datasize<<14)|2;
139  cmdbuf[4]=(u32)data;
140  cmdbuf[5]=(masksize<<14)|0x402;
141  cmdbuf[6]=(u32)maskdata;
142 
143  Result ret=0;
144  if((ret=svcSendSyncRequest(*handle)))return ret;
145 
146  return cmdbuf[1];
147 }
148 
149 Result GSPGPU_ReadHWRegs(Handle* handle, u32 regAddr, u32* data, u8 size)
150 {
151  if(!handle)handle=&gspGpuHandle;
152 
153  if(size>0x80 || !data)return -1;
154 
155  u32* cmdbuf=getThreadCommandBuffer();
156  cmdbuf[0]=0x00040080; //request header code
157  cmdbuf[1]=regAddr;
158  cmdbuf[2]=size;
159  cmdbuf[0x40]=(size<<14)|2;
160  cmdbuf[0x40+1]=(u32)data;
161 
162  Result ret=0;
163  if((ret=svcSendSyncRequest(*handle)))return ret;
164 
165  return cmdbuf[1];
166 }
167 
168 Result GSPGPU_SetBufferSwap(Handle* handle, u32 screenid, GSP_FramebufferInfo *framebufinfo)
169 {
170  Result ret=0;
171  u32 *cmdbuf = getThreadCommandBuffer();
172 
173  if(!handle)handle=&gspGpuHandle;
174 
175  cmdbuf[0] = 0x00050200;
176  cmdbuf[1] = screenid;
177  memcpy(&cmdbuf[2], framebufinfo, sizeof(GSP_FramebufferInfo));
178 
179  if((ret=svcSendSyncRequest(*handle)))return ret;
180 
181  return cmdbuf[1];
182 }
183 
185 {
186  if(!handle)handle=&gspGpuHandle;
187 
188  u32* cmdbuf=getThreadCommandBuffer();
189  cmdbuf[0]=0x00080082; //request header code
190  cmdbuf[1]=(u32)adr;
191  cmdbuf[2]=size;
192  cmdbuf[3]=0x0;
193  cmdbuf[4]=0xffff8001;
194 
195  Result ret=0;
196  if((ret=svcSendSyncRequest(*handle)))return ret;
197 
198  return cmdbuf[1];
199 }
200 
202 {
203  Result ret=0;
204  u32 *cmdbuf = getThreadCommandBuffer();
205 
206  if(!handle)handle=&gspGpuHandle;
207 
208  cmdbuf[0] = 0x00090082;
209  cmdbuf[1] = (u32)adr;
210  cmdbuf[2] = size;
211  cmdbuf[3] = 0;
212  cmdbuf[4] = 0xFFFF8001;
213 
214  if((ret=svcSendSyncRequest(*handle)))return ret;
215 
216  return cmdbuf[1];
217 }
218 
220 {
221  if(!handle)handle=&gspGpuHandle;
222 
223  u32* cmdbuf=getThreadCommandBuffer();
224  cmdbuf[0]=0x000B0040; //request header code
225  cmdbuf[1]=flags;
226 
227  Result ret=0;
228  if((ret=svcSendSyncRequest(*handle)))return ret;
229 
230  return cmdbuf[1];
231 }
232 
234 {
235  if(!handle)handle=&gspGpuHandle;
236 
237  u32* cmdbuf=getThreadCommandBuffer();
238  cmdbuf[0]=0x000C0000; //request header code
239 
240  Result ret=0;
241  if((ret=svcSendSyncRequest(*handle)))return ret;
242 
243  return cmdbuf[1];
244 }
245 
246 Result GSPGPU_RegisterInterruptRelayQueue(Handle* handle, Handle eventHandle, u32 flags, Handle* outMemHandle, u8* threadID)
247 {
248  if(!handle)handle=&gspGpuHandle;
249 
250  u32* cmdbuf=getThreadCommandBuffer();
251  cmdbuf[0]=0x00130042; //request header code
252  cmdbuf[1]=flags;
253  cmdbuf[2]=0x0;
254  cmdbuf[3]=eventHandle;
255 
256  Result ret=0;
257  if((ret=svcSendSyncRequest(*handle)))return ret;
258 
259  if(threadID)*threadID=cmdbuf[2];
260  if(outMemHandle)*outMemHandle=cmdbuf[4];
261 
262  return cmdbuf[1];
263 }
264 
266 {
267  if(!handle)handle=&gspGpuHandle;
268 
269  u32* cmdbuf=getThreadCommandBuffer();
270  cmdbuf[0]=0x00140000; //request header code
271 
272  Result ret=0;
273  if((ret=svcSendSyncRequest(*handle)))return ret;
274 
275  return cmdbuf[1];
276 }
277 
279 {
280  if(!handle)handle=&gspGpuHandle;
281 
282  u32* cmdbuf=getThreadCommandBuffer();
283  cmdbuf[0]=0x160042; //request header code
284  cmdbuf[1]=flags;
285  cmdbuf[2]=0x0;
286  cmdbuf[3]=0xffff8001;
287 
288  Result ret=0;
289  if((ret=svcSendSyncRequest(*handle)))return ret;
290 
291  return cmdbuf[1];
292 }
293 
295 {
296  if(!handle)handle=&gspGpuHandle;
297 
298  u32* cmdbuf=getThreadCommandBuffer();
299  cmdbuf[0]=0x170000; //request header code
300 
301  Result ret=0;
302  if((ret=svcSendSyncRequest(*handle)))return ret;
303 
304  return cmdbuf[1];
305 }
306 
308 {
309  if(!handle)handle=&gspGpuHandle;
310 
311  u32* cmdbuf=getThreadCommandBuffer();
312  cmdbuf[0]=0x00180000; //request header code
313 
314  Result ret=0;
315  if((ret=svcSendSyncRequest(*handle)))return ret;
316 
317  ret = cmdbuf[1];
318 
319  if(ret==0)
320  {
321  memcpy(captureinfo, &cmdbuf[2], 0x20);
322  }
323 
324  return ret;
325 }
326 
328 {
329  if(!handle)handle=&gspGpuHandle;
330 
331  u32* cmdbuf=getThreadCommandBuffer();
332  cmdbuf[0]=0x00190000; //request header code
333 
334  Result ret=0;
335  if((ret=svcSendSyncRequest(*handle)))return ret;
336 
337  return cmdbuf[1];
338 }
339 
341 {
342  if(!handle)handle=&gspGpuHandle;
343 
344  u32* cmdbuf=getThreadCommandBuffer();
345  cmdbuf[0]=0x001A0000; //request header code
346 
347  Result ret=0;
348  if((ret=svcSendSyncRequest(*handle)))return ret;
349 
350  return cmdbuf[1];
351 }
352 
353 //essentially : get commandIndex and totalCommands, calculate offset of new command, copy command and update totalCommands
354 //use LDREX/STREX because this data may also be accessed by the GSP module and we don't want to break stuff
355 //(mostly, we could overwrite the buffer header with wrong data and make the GSP module reexecute old commands)
356 Result GSPGPU_SubmitGxCommand(u32* sharedGspCmdBuf, u32 gxCommand[0x8], Handle* handle)
357 {
358  if(!sharedGspCmdBuf || !gxCommand)return -1;
359 
360  u32 cmdBufHeader;
361  __asm__ __volatile__ ("ldrex %[result], [%[adr]]" : [result] "=r" (cmdBufHeader) : [adr] "r" (sharedGspCmdBuf));
362 
363  u8 commandIndex=cmdBufHeader&0xFF;
364  u8 totalCommands=(cmdBufHeader>>8)&0xFF;
365 
366  if(totalCommands>=15)return -2;
367 
368  u8 nextCmd=(commandIndex+totalCommands)%15; //there are 15 command slots
369  u32* dst=&sharedGspCmdBuf[8*(1+nextCmd)];
370  memcpy(dst, gxCommand, 0x20);
371 
372  u32 mcrVal=0x0;
373  __asm__ __volatile__ ("mcr p15, 0, %[val], c7, c10, 4" :: [val] "r" (mcrVal)); //Data Synchronization Barrier Register
374  totalCommands++;
375  cmdBufHeader=((cmdBufHeader)&0xFFFF00FF)|(((u32)totalCommands)<<8);
376 
377  while(1)
378  {
379  u32 strexResult;
380  __asm__ __volatile__ ("strex %[result], %[val], [%[adr]]" : [result] "=&r" (strexResult) : [adr] "r" (sharedGspCmdBuf), [val] "r" (cmdBufHeader));
381  if(!strexResult)break;
382 
383  __asm__ __volatile__ ("ldrex %[result], [%[adr]]" : [result] "=r" (cmdBufHeader) : [adr] "r" (sharedGspCmdBuf));
384  totalCommands=((cmdBufHeader&0xFF00)>>8)+1;
385  cmdBufHeader=((cmdBufHeader)&0xFFFF00FF)|((totalCommands<<8)&0xFF00);
386  }
387 
388  if(totalCommands==1)return GSPGPU_TriggerCmdReqQueue(handle);
389  return 0;
390 }
s32 svcClearEvent(Handle handle)
s32 Result
Definition: types.h:42
Result GSPGPU_ImportDisplayCaptureInfo(Handle *handle, GSP_CaptureInfo *captureinfo)
Definition: gsp.c:307
s32 svcCloseHandle(Handle handle)
s32 svcWaitSynchronization(Handle handle, s64 nanoseconds)
s32 svcCreateThread(Handle *thread, ThreadFunc entrypoint, u32 arg, u32 *stack_top, s32 thread_priority, s32 processor_id)
Result srvGetServiceHandle(Handle *out, const char *name)
Definition: srv.c:109
Result GSPGPU_ReleaseRight(Handle *handle)
Definition: gsp.c:294
Handle gspEventThread
Definition: gsp.c:15
Result GSPGPU_SubmitGxCommand(u32 *sharedGspCmdBuf, u32 gxCommand[0x8], Handle *handle)
Definition: gsp.c:356
Result GSPGPU_WriteHWRegs(Handle *handle, u32 regAddr, u32 *data, u8 size)
Definition: gsp.c:109
Result gspInitEventHandler(Handle _gspEvent, vu8 *_gspSharedMem, u8 gspThreadId)
Definition: gsp.c:33
u32 Handle
Definition: types.h:41
volatile u8 vu8
Definition: types.h:31
Handle gspEvent
Definition: gfx.c:18
GSP_Event
Definition: gsp.h:38
#define U64_MAX
Definition: types.h:12
Result GSPGPU_RestoreVramSysArea(Handle *handle)
Definition: gsp.c:340
Result GSPGPU_WriteHWRegsWithMask(Handle *handle, u32 regAddr, u32 *data, u8 datasize, u32 *maskdata, u8 masksize)
Definition: gsp.c:128
u32 * getThreadCommandBuffer(void)
uint8_t u8
Definition: types.h:21
Result GSPGPU_FlushDataCache(Handle *handle, u8 *adr, u32 size)
Definition: gsp.c:184
uint64_t u64
Definition: types.h:24
volatile bool gspRunEvents
Definition: gsp.c:14
void gspExit()
Definition: gsp.c:28
Result GSPGPU_SaveVramSysArea(Handle *handle)
Definition: gsp.c:327
uint32_t u32
Definition: types.h:23
Result GSPGPU_TriggerCmdReqQueue(Handle *handle)
Definition: gsp.c:233
Handle gspGpuHandle
Definition: gsp.c:11
void gspWaitForEvent(GSP_Event id, bool nextEvent)
Definition: gsp.c:70
Result gspInit()
Definition: gsp.c:23
Result GSPGPU_ReadHWRegs(Handle *handle, u32 regAddr, u32 *data, u8 size)
Definition: gsp.c:149
Result GSPGPU_SetLcdForceBlack(Handle *handle, u8 flags)
Definition: gsp.c:219
s32 svcCreateEvent(Handle *event, u8 reset_type)
Result GSPGPU_SetBufferSwap(Handle *handle, u32 screenid, GSP_FramebufferInfo *framebufinfo)
Definition: gsp.c:168
Handle gspEvents[GSPEVENT_MAX]
Definition: gsp.c:12
s32 svcSendSyncRequest(Handle session)
Result GSPGPU_InvalidateDataCache(Handle *handle, u8 *adr, u32 size)
Definition: gsp.c:201
Result GSPGPU_UnregisterInterruptRelayQueue(Handle *handle)
Definition: gsp.c:265
Result GSPGPU_AcquireRight(Handle *handle, u8 flags)
Definition: gsp.c:278
s32 svcSignalEvent(Handle handle)
#define GSP_EVENT_STACK_SIZE
Definition: gsp.c:9
u64 gspEventStack[GSP_EVENT_STACK_SIZE/sizeof(u64)]
Definition: gsp.c:13
Result GSPGPU_RegisterInterruptRelayQueue(Handle *handle, Handle eventHandle, u32 flags, Handle *outMemHandle, u8 *threadID)
Definition: gsp.c:246
void gspExitEventHandler()
Definition: gsp.c:57