1 /*
2 * Copyright 2017 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can
5 * be found in the LICENSE file.
6 *
7 */
8
9 //
10 //
11 //
12
13 #include "common/cl/assert_cl.h"
14
15 #include "skc_cl.h"
16 #include "interop.h"
17 #include "extent_cl_12.h"
18 #include "runtime_cl_12.h"
19 #include "styling_cl_12.h"
20 #include "composition_cl_12.h"
21
22 #include "context.h"
23 #include "surface.h"
24
25 //
26 //
27 //
28
29 #include <stdio.h>
30
31 //
32 // BUILD
33 //
34
35 struct skc_surface_impl
36 {
37 struct skc_surface * surface;
38 struct skc_runtime * runtime;
39
40 // framebuffer
41 // struct skc_extent_pdrw fb;
42 // struct skc_extent_phrN_pdwN fb;
43
44 // for now, a single in-order command queue
45 cl_command_queue cq;
46
47 struct {
48 cl_kernel render;
49 } kernels;
50 };
51
52 //
53 //
54 //
55
56 struct skc_surface_render
57 {
58 skc_uint clip[4];
59 skc_uint txty[2];
60
61 struct skc_surface_impl * impl;
62 struct skc_styling * styling;
63 struct skc_composition * composition;
64
65 struct skc_framebuffer_cl * fb;
66
67 skc_surface_render_notify notify;
68 void * data;
69
70 skc_grid_t grid;
71
72 skc_subbuf_id_t id;
73 };
74
75 //
76 // FIXME -- we only need this because (I think) RBO<>CL interop
77 // results in glClear() on the FBO not working...
78 //
79
80 static
81 void
skc_surface_debug_clear(struct skc_surface_impl * const impl,skc_framebuffer_t fb,float const rgba[4],uint32_t const rect[4])82 skc_surface_debug_clear(struct skc_surface_impl * const impl,
83 skc_framebuffer_t fb,
84 float const rgba[4],
85 uint32_t const rect[4])
86 {
87 size_t const origin[3] = { rect[0], rect[1], 0 };
88 size_t const region[3] = { rect[2], rect[3], 1 };
89
90 cl(EnqueueFillImage(impl->cq,
91 ((struct skc_framebuffer_cl *)fb)->mem,
92 rgba,
93 origin,
94 region,
95 0,NULL,NULL));
96 }
97
98 //
99 //
100 //
101
102 #if 0 // #ifndef NDEBUG
103
104 static
105 void
106 skc_surface_debug(struct skc_surface_impl * const impl)
107 {
108 //
109 // MAP
110 //
111 cl_uchar4 * const rgba = skc_extent_phrN_pdwN_map(&impl->fb,
112 impl->cq,
113 NULL);
114 cl(Finish(impl->cq));
115
116 //
117 // WRITE
118 //
119 FILE* file;
120
121 errno_t ferr = fopen_s(&file,"surface.ppm","wb");
122
123 fprintf(file,"P6\n%u %u\n255\n",SKC_SURFACE_WIDTH,SKC_SURFACE_HEIGHT);
124
125 for (skc_uint ii=0; ii<SKC_SURFACE_HEIGHT*SKC_SURFACE_WIDTH; ii++)
126 fwrite(rgba + ii,sizeof(skc_uchar),3,file); // R,G,B
127
128 ferr = fclose(file);
129
130 //
131 // UNMAP
132 //
133 skc_extent_phrN_pdwN_unmap(&impl->fb,rgba,impl->cq,NULL);
134
135 cl(Flush(impl->cq));
136 }
137
138 #endif
139
140 //
141 //
142 //
143
144 static
145 void
skc_surface_pfn_release(struct skc_surface_impl * const impl)146 skc_surface_pfn_release(struct skc_surface_impl * const impl)
147 {
148 if (--impl->surface->ref_count != 0)
149 return;
150
151 //
152 // otherwise, release all resources
153 //
154
155 // drain the command queue
156 cl(Finish(impl->cq));
157
158 struct skc_runtime * const runtime = impl->runtime;
159
160 // release the kernel
161 cl(ReleaseKernel(impl->kernels.render));
162
163 // free surface host
164 skc_runtime_host_perm_free(runtime,impl->surface);
165
166 // release the cq
167 skc_runtime_release_cq_in_order(runtime,impl->cq);
168
169 // release fb
170 // skc_extent_phrN_pdwN_free(runtime,&impl->fb);
171
172 // free surface impl
173 skc_runtime_host_perm_free(runtime,impl);
174 }
175
176 //
177 //
178 //
179
180 void
skc_surface_render_complete(struct skc_surface_render * const render)181 skc_surface_render_complete(struct skc_surface_render * const render)
182 {
183 #ifdef SKC_SURFACE_DEBUG
184 // write fb out
185 skc_surface_debug(render->impl);
186 #endif
187
188 // notify
189 if (render->notify != NULL) {
190 render->notify(render->impl->surface,
191 render->styling,
192 render->composition,
193 render->fb,
194 render->data);
195 }
196
197 // unlock and release the styling and composition
198 skc_styling_unlock_and_release(render->styling);
199 skc_composition_unlock_and_release(render->composition);
200
201 // grid is now complete
202 skc_grid_complete(render->grid);
203
204 struct skc_surface_impl * const impl = render->impl;
205 struct skc_runtime * const runtime = impl->runtime;
206
207 // release the surface
208 skc_surface_pfn_release(impl);
209
210 // free the render object
211 skc_runtime_host_temp_free(runtime,render,render->id);
212 }
213
214 static
215 void
skc_surface_render_cb(cl_event event,cl_int status,struct skc_surface_render * const render)216 skc_surface_render_cb(cl_event event, cl_int status, struct skc_surface_render * const render)
217 {
218 SKC_CL_CB(status);
219
220 // as quickly as possible, enqueue next stage in pipeline to context command scheduler
221 SKC_SCHEDULER_SCHEDULE(render->impl->runtime->scheduler,
222 skc_surface_render_complete,
223 render);
224 }
225
226 //
227 //
228 //
229
230 static
231 void
skc_surface_grid_pfn_execute(skc_grid_t const grid)232 skc_surface_grid_pfn_execute(skc_grid_t const grid)
233 {
234 struct skc_surface_render * const render = skc_grid_get_data(grid);
235 struct skc_surface_impl * const impl = render->impl;
236 struct skc_runtime * const runtime = impl->runtime;
237
238 // get the composition args
239 struct skc_composition_impl * const ci = render->composition->impl;
240 struct skc_place_atomics * const atomics = ci->atomics.hr;
241
242 if (atomics->offsets > 0)
243 {
244 // acquire the rbo/tex
245 if (render->fb->type != SKC_FRAMEBUFFER_CL_IMAGE2D)
246 cl(EnqueueAcquireGLObjects(impl->cq,1,&render->fb->mem,0,NULL,NULL));
247
248 // get the styling args
249 struct skc_styling_impl * const si = render->styling->impl;
250
251 cl(SetKernelArg(impl->kernels.render,0,SKC_CL_ARG(si->layers.drN)));
252 cl(SetKernelArg(impl->kernels.render,1,SKC_CL_ARG(si->groups.drN)));
253 cl(SetKernelArg(impl->kernels.render,2,SKC_CL_ARG(si->extras.drN)));
254
255 cl(SetKernelArg(impl->kernels.render,3,SKC_CL_ARG(ci->keys.drw)));
256 cl(SetKernelArg(impl->kernels.render,4,SKC_CL_ARG(atomics->keys)));
257 cl(SetKernelArg(impl->kernels.render,5,SKC_CL_ARG(ci->offsets.drw)));
258 cl(SetKernelArg(impl->kernels.render,6,SKC_CL_ARG(atomics->offsets)));
259
260 // block pool
261 cl(SetKernelArg(impl->kernels.render,7,SKC_CL_ARG(impl->runtime->block_pool.blocks.drw)));
262
263 // surface
264 cl(SetKernelArg(impl->kernels.render,8,SKC_CL_ARG(render->fb->mem)));
265
266 #if 1
267 // tile clip
268 cl(SetKernelArg(impl->kernels.render,9,sizeof(skc_uint4),render->clip));
269 #else
270 // surface pitch (height)
271 skc_uint const surface_pitch = SKC_SURFACE_HEIGHT;
272 cl(SetKernelArg(impl->kernels.render,9,SKC_CL_ARG(surface_pitch)));
273 // tile clip
274 cl(SetKernelArg(impl->kernels.render,10,sizeof(skc_uint4),render->clip));
275 #endif
276
277 // launch render kernel
278 skc_device_enqueue_kernel(runtime->device,
279 SKC_DEVICE_KERNEL_ID_RENDER,
280 impl->cq,
281 impl->kernels.render,
282 atomics->offsets,
283 0,NULL,NULL);
284
285
286 cl_event complete;
287
288 // give the rbo back
289 if (render->fb->type != SKC_FRAMEBUFFER_CL_IMAGE2D)
290 {
291 cl(EnqueueReleaseGLObjects(impl->cq,1,&render->fb->mem,0,NULL,&complete));
292
293 //
294 // blit the rbo to fbo0
295 //
296 render->fb->post_render(render->fb->interop);
297
298 //
299 // clear the rbo -- FIXME -- we shouldn't have to do this here
300 //
301 float const rgba[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
302 uint32_t rect[4] = { 0 };
303
304 skc_interop_get_size(render->fb->interop,rect+2,rect+3);
305
306 skc_surface_debug_clear(impl,render->fb,rgba,rect);
307 }
308
309 // notify anyone listening...
310 cl(SetEventCallback(complete,CL_COMPLETE,skc_surface_render_cb,render));
311 cl(ReleaseEvent(complete));
312
313 // flush it
314 cl(Flush(impl->cq));
315 }
316 else
317 {
318 skc_surface_render_complete(render);
319 }
320 }
321
322 //
323 //
324 //
325
326 static
327 void
skc_surface_pfn_render(struct skc_surface_impl * const impl,skc_styling_t styling,skc_composition_t composition,skc_framebuffer_t fb,uint32_t const clip[4],int32_t const txty[2],skc_surface_render_notify notify,void * data)328 skc_surface_pfn_render(struct skc_surface_impl * const impl,
329 skc_styling_t styling,
330 skc_composition_t composition,
331 skc_framebuffer_t fb,
332 uint32_t const clip[4],
333 int32_t const txty[2],
334 skc_surface_render_notify notify,
335 void * data)
336 {
337 // retain surface
338 skc_surface_retain(impl->surface);
339
340 //
341 // FIXME -- we used to seal the styling and composition objects if
342 // they weren't already. Either test that they're sealed or seal
343 // them here.
344 //
345
346 // retain and lock the styling and composition
347 skc_styling_retain_and_lock(styling);
348 skc_composition_retain_and_lock(composition);
349
350 //
351 // allocate a render instance
352 //
353 skc_subbuf_id_t id;
354 struct skc_surface_render * const render = skc_runtime_host_temp_alloc(impl->runtime,
355 SKC_MEM_FLAGS_READ_WRITE,
356 sizeof(*render),&id,NULL);
357 render->id = id;
358
359 render->clip[0] = clip[0];
360 render->clip[1] = clip[1];
361 render->clip[2] = clip[2];
362 render->clip[3] = clip[3];
363
364 render->txty[0] = txty[0];
365 render->txty[1] = txty[1];
366
367 render->impl = impl;
368 render->styling = styling;
369 render->composition = composition;
370
371 render->notify = notify;
372 render->data = data;
373
374 render->fb = fb;
375
376 render->grid = SKC_GRID_DEPS_ATTACH(impl->runtime->deps,
377 NULL, // invalidation not necessary
378 render,
379 NULL, // no waiting
380 skc_surface_grid_pfn_execute,
381 NULL); // no disposal
382 //
383 // declare happens-after relationships
384 //
385 if (styling->impl->state != SKC_STYLING_STATE_SEALED)
386 skc_grid_happens_after_grid(render->grid,styling->impl->grid);
387
388 if (composition->impl->state != SKC_COMPOSITION_STATE_SEALED)
389 skc_grid_happens_after_grid(render->grid,composition->impl->grids.sort);
390
391 //
392 // start render but possibly wait for styling and composition
393 //
394 skc_grid_start(render->grid);
395 }
396
397 //
398 //
399 //
400
401 skc_err
skc_surface_cl_12_create(struct skc_context * const context,struct skc_surface ** const surface)402 skc_surface_cl_12_create(struct skc_context * const context,
403 struct skc_surface * * const surface)
404 {
405 struct skc_runtime * const runtime = context->runtime;
406
407 // allocate surface
408 (*surface) = skc_runtime_host_perm_alloc(runtime,SKC_MEM_FLAGS_READ_WRITE,sizeof(**surface));
409
410 // allocate impl
411 struct skc_surface_impl * const impl = skc_runtime_host_perm_alloc(runtime,SKC_MEM_FLAGS_READ_WRITE,sizeof(*impl));
412
413 // initialize surface
414 // SKC_ASSERT_STATE_INIT((*impl),SKC_SURFACE_STATE_READY);
415
416 (*surface)->context = context;
417 (*surface)->impl = impl;
418 (*surface)->ref_count = 1;
419
420 (*surface)->release = skc_surface_pfn_release;
421 (*surface)->render = skc_surface_pfn_render;
422
423 // intialize impl
424 impl->surface = *surface;
425 impl->runtime = runtime;
426
427 #if 0
428 // FIXME -- 4K x 4K -- temporarily fixed size
429 size_t const fb_size = sizeof(skc_uchar4) * SKC_SURFACE_WIDTH * SKC_SURFACE_HEIGHT;
430
431 // create framebuffer
432 skc_extent_phrN_pdwN_alloc(runtime,&impl->fb,fb_size);
433 #endif
434
435 // acquire a command queue
436 impl->cq = skc_runtime_acquire_cq_in_order(runtime);
437
438 // acquire kernel
439 impl->kernels.render = skc_device_acquire_kernel(runtime->device,SKC_DEVICE_KERNEL_ID_RENDER);
440
441 return SKC_ERR_SUCCESS;
442 }
443
444 //
445 //
446 //
447