spu: don't block on audio
[pcsx_rearmed.git] / plugins / dfsound / spu_c64x.c
CommitLineData
5514a050 1/*
2 * SPU processing offload to TI C64x DSP using bsp's c64_tools
3 * (C) GraÅžvydas "notaz" Ignotas, 2015
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy of
6 * this software and associated documentation files (the "Software"), to deal in
7 * the Software without restriction, including without limitation the rights to
8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9 * of the Software, and to permit persons to whom the Software is furnished to do
10 * so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in all
13 * copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
24#include <dlfcn.h>
de4a0279 25#include <stddef.h>
3bd31caf 26#include <unistd.h>
de4a0279 27
5514a050 28#include <inc_libc64_mini.h>
29#include "spu_c64x.h"
30
5514a050 31static struct {
32 void *handle;
33 int (*dsp_open)(void);
34 dsp_mem_region_t (*dsp_shm_alloc)(dsp_cache_t _type, sU32 _numBytes);
35 int (*dsp_shm_free)(dsp_mem_region_t _mem);
36 void (*dsp_close)(void);
37 int (*dsp_component_load)(const char *_path, const char *_name, dsp_component_id_t *_id);
38 int (*dsp_cache_inv_virt)(void *_virtAddr, sU32 _size);
39 int (*dsp_rpc_send)(const dsp_msg_t *_msgTo);
40 int (*dsp_rpc_recv)(dsp_msg_t *_msgFrom);
de4a0279 41 int (*dsp_rpc)(const dsp_msg_t *_msgTo, dsp_msg_t *_msgFrom);
5514a050 42 void (*dsp_logbuf_print)(void);
3bd31caf 43
44 dsp_mem_region_t region;
45 dsp_component_id_t compid;
5514a050 46} f;
47
48static void thread_work_start(void)
49{
3bd31caf 50 struct region_mem *mem;
de4a0279 51 dsp_msg_t msg;
52 int ret;
53
3bd31caf 54 // make sure new work is written out
55 __sync_synchronize();
56
57 // this should be safe, as dsp checks for new work even
58 // after it decrements ->active
59 // cacheline: i_done, active
60 f.dsp_cache_inv_virt(&worker->i_done, 64);
61 if (worker->active == ACTIVE_CNT)
62 return;
63
64 // to start the DSP, dsp_rpc_send() must be used,
65 // but before that, previous request must be finished
66 if (worker->req_sent) {
67 if (worker->boot_cnt == worker->last_boot_cnt) {
68 // hopefully still booting
69 //printf("booting?\n");
70 return;
71 }
72
73 ret = f.dsp_rpc_recv(&msg);
74 if (ret != 0) {
75 fprintf(stderr, "dsp_rpc_recv failed: %d\n", ret);
76 f.dsp_logbuf_print();
77 worker->req_sent = 0;
78 spu_config.iUseThread = 0;
79 return;
80 }
81 }
82
83 f.dsp_cache_inv_virt(&worker->i_done, 64);
84 worker->last_boot_cnt = worker->boot_cnt;
85
86 mem = (void *)f.region.virt_addr;
87 memcpy(&mem->spu_config, &spu_config, sizeof(mem->spu_config));
88
89 DSP_MSG_INIT(&msg, f.compid, CCMD_DOIT, f.region.phys_addr, 0);
de4a0279 90 ret = f.dsp_rpc_send(&msg);
91 if (ret != 0) {
92 fprintf(stderr, "dsp_rpc_send failed: %d\n", ret);
93 f.dsp_logbuf_print();
3bd31caf 94 spu_config.iUseThread = 0;
95 return;
de4a0279 96 }
3bd31caf 97 worker->req_sent = 1;
5514a050 98}
99
3bd31caf 100static int thread_get_i_done(void)
5514a050 101{
3bd31caf 102 f.dsp_cache_inv_virt(&worker->i_done, sizeof(worker->i_done));
103 return worker->i_done;
104}
105
106static void thread_work_wait_sync(struct work_item *work, int force)
107{
108 int limit = 1000;
de4a0279 109 int ns_to;
de4a0279 110
3bd31caf 111 ns_to = work->ns_to;
112 f.dsp_cache_inv_virt(work->RVB, sizeof(work->RVB[0]) * 2 * ns_to);
113 f.dsp_cache_inv_virt(work->SSumLR, sizeof(work->SSumLR[0]) * 2 * ns_to);
114 __builtin_prefetch(work->RVB);
115 __builtin_prefetch(work->SSumLR);
de4a0279 116
3bd31caf 117 while (worker->i_done == worker->i_reaped && limit-- > 0) {
118 if (!worker->active) {
119 printf("dsp: broken sync\n");
120 worker->last_boot_cnt = ~0;
121 break;
122 }
123
124 usleep(500);
125 f.dsp_cache_inv_virt(&worker->i_done, 64);
de4a0279 126 }
de4a0279 127
3bd31caf 128 if (limit == 0)
129 printf("dsp: wait timeout\n");
130
131 // still in results loop?
132 if (worker->i_reaped != worker->i_done - 1)
133 return;
134
135 if (worker->req_sent && (force || worker->i_done == worker->i_ready)) {
136 dsp_msg_t msg;
137 int ret;
138
139 ret = f.dsp_rpc_recv(&msg);
140 if (ret != 0) {
141 fprintf(stderr, "dsp_rpc_recv failed: %d\n", ret);
142 f.dsp_logbuf_print();
143 spu_config.iUseThread = 0;
144 }
145 worker->req_sent = 0;
146 }
147
148 if (force) {
de4a0279 149 f.dsp_cache_inv_virt(spu.SB, sizeof(spu.SB[0]) * SB_SIZE * 24);
150 f.dsp_cache_inv_virt(spu.spuMemC + 0x800, 0x800);
de4a0279 151 }
5514a050 152}
153
154static void init_spu_thread(void)
155{
de4a0279 156 dsp_msg_t init_msg, msg_in;
5514a050 157 struct region_mem *mem;
158 int ret;
159
160 if (f.handle == NULL) {
161 const char lib[] = "libc64.so.1";
162 int failed = 0;
163
164 f.handle = dlopen(lib, RTLD_NOW);
165 if (f.handle == NULL) {
166 fprintf(stderr, "can't load %s: %s\n", lib, dlerror());
3bd31caf 167 goto fail_open;
5514a050 168 }
169 #define LDS(name) \
170 failed |= (f.name = dlsym(f.handle, #name)) == NULL
171 LDS(dsp_open);
172 LDS(dsp_close);
173 LDS(dsp_shm_alloc);
174 LDS(dsp_shm_free);
175 LDS(dsp_cache_inv_virt);
176 LDS(dsp_component_load);
177 LDS(dsp_rpc_send);
178 LDS(dsp_rpc_recv);
de4a0279 179 LDS(dsp_rpc);
5514a050 180 LDS(dsp_logbuf_print);
181 #undef LDS
182 if (failed) {
183 fprintf(stderr, "missing symbol(s) in %s\n", lib);
184 dlclose(f.handle);
185 f.handle = NULL;
3bd31caf 186 goto fail_open;
5514a050 187 }
188 }
189
190 ret = f.dsp_open();
191 if (ret != 0) {
192 fprintf(stderr, "dsp_open failed: %d\n", ret);
3bd31caf 193 goto fail_open;
5514a050 194 }
195
3bd31caf 196 ret = f.dsp_component_load(NULL, COMPONENT_NAME, &f.compid);
de4a0279 197 if (ret != 0) {
198 fprintf(stderr, "dsp_component_load failed: %d\n", ret);
199 goto fail_cload;
200 }
201
3bd31caf 202 f.region = f.dsp_shm_alloc(DSP_CACHE_R, sizeof(*mem)); // writethrough
203 if (f.region.size < sizeof(*mem) || f.region.virt_addr == 0) {
5514a050 204 fprintf(stderr, "dsp_shm_alloc failed\n");
205 goto fail_mem;
206 }
3bd31caf 207 mem = (void *)f.region.virt_addr;
5514a050 208
de4a0279 209 memcpy(&mem->spu_config, &spu_config, sizeof(mem->spu_config));
210
3bd31caf 211 DSP_MSG_INIT(&init_msg, f.compid, CCMD_INIT, f.region.phys_addr, 0);
de4a0279 212 ret = f.dsp_rpc(&init_msg, &msg_in);
213 if (ret != 0) {
214 fprintf(stderr, "dsp_rpc failed: %d\n", ret);
215 goto fail_init;
216 }
217
218 if (mem->sizeof_region_mem != sizeof(*mem)) {
219 fprintf(stderr, "error: size mismatch 1: %d vs %zd\n",
220 mem->sizeof_region_mem, sizeof(*mem));
221 goto fail_init;
222 }
223 if (mem->offsetof_s_chan1 != offsetof(typeof(*mem), s_chan[1])) {
224 fprintf(stderr, "error: size mismatch 2: %d vs %zd\n",
225 mem->offsetof_s_chan1, offsetof(typeof(*mem), s_chan[1]));
226 goto fail_init;
227 }
3bd31caf 228 if (mem->offsetof_spos_3_20 != offsetof(typeof(*mem), worker.i[3].ch[20])) {
de4a0279 229 fprintf(stderr, "error: size mismatch 3: %d vs %zd\n",
3bd31caf 230 mem->offsetof_spos_3_20, offsetof(typeof(*mem), worker.i[3].ch[20]));
de4a0279 231 goto fail_init;
232 }
233
5514a050 234 // override default allocations
235 free(spu.spuMemC);
236 spu.spuMemC = mem->spu_ram;
de4a0279 237 free(spu.SB);
238 spu.SB = mem->SB;
5514a050 239 free(spu.s_chan);
240 spu.s_chan = mem->s_chan;
241 worker = &mem->worker;
242
3bd31caf 243 printf("spu: C64x DSP ready (id=%d).\n", (int)f.compid);
de4a0279 244 f.dsp_logbuf_print();
245
3bd31caf 246 spu_config.iThreadAvail = 1;
de4a0279 247 (void)do_channel_work; // used by DSP instead
5514a050 248 return;
249
de4a0279 250fail_init:
3bd31caf 251 f.dsp_shm_free(f.region);
5514a050 252fail_mem:
de4a0279 253 // no component unload func?
254fail_cload:
de4a0279 255 f.dsp_logbuf_print();
5514a050 256 f.dsp_close();
3bd31caf 257fail_open:
258 printf("spu: C64x DSP init failed.\n");
259 spu_config.iUseThread = spu_config.iThreadAvail = 0;
5514a050 260 worker = NULL;
261}
262
263static void exit_spu_thread(void)
264{
3bd31caf 265 dsp_msg_t msg;
266
5514a050 267 if (worker == NULL)
268 return;
269
3bd31caf 270 if (worker->req_sent)
271 f.dsp_rpc_recv(&msg);
272
273 f.dsp_logbuf_print();
274 f.dsp_shm_free(f.region);
5514a050 275 f.dsp_close();
276
277 spu.spuMemC = NULL;
de4a0279 278 spu.SB = NULL;
5514a050 279 spu.s_chan = NULL;
280 worker = NULL;
281}
282
283// vim:shiftwidth=1:expandtab