Branch data Line data Source code
1 : : /*
2 : : * This file is part of libplacebo.
3 : : *
4 : : * libplacebo is free software; you can redistribute it and/or
5 : : * modify it under the terms of the GNU Lesser General Public
6 : : * License as published by the Free Software Foundation; either
7 : : * version 2.1 of the License, or (at your option) any later version.
8 : : *
9 : : * libplacebo is distributed in the hope that it will be useful,
10 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : : * GNU Lesser General Public License for more details.
13 : : *
14 : : * You should have received a copy of the GNU Lesser General Public
15 : : * License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
16 : : */
17 : :
18 : : #include <limits.h>
19 : : #include <string.h>
20 : :
21 : : #include "gpu.h"
22 : :
23 : : #include <libplacebo/dummy.h>
24 : :
25 : : const struct pl_gpu_dummy_params pl_gpu_dummy_default_params = { PL_GPU_DUMMY_DEFAULTS };
26 : : static const struct pl_gpu_fns pl_fns_dummy;
27 : :
28 : : struct priv {
29 : : struct pl_gpu_fns impl;
30 : : struct pl_gpu_dummy_params params;
31 : : };
32 : :
33 : 2 : pl_gpu pl_gpu_dummy_create(pl_log log, const struct pl_gpu_dummy_params *params)
34 : : {
35 [ + - ]: 2 : params = PL_DEF(params, &pl_gpu_dummy_default_params);
36 : :
37 : 2 : struct pl_gpu_t *gpu = pl_zalloc_obj(NULL, gpu, struct priv);
38 : 2 : gpu->log = log;
39 : 2 : gpu->glsl = params->glsl;
40 : 2 : gpu->limits = params->limits;
41 : :
42 : 2 : struct priv *p = PL_PRIV(gpu);
43 : 2 : p->impl = pl_fns_dummy;
44 : 2 : p->params = *params;
45 : :
46 : : // Forcibly override these, because we know for sure what the values are
47 : 2 : gpu->limits.align_tex_xfer_pitch = 1;
48 : 2 : gpu->limits.align_tex_xfer_offset = 1;
49 : 2 : gpu->limits.align_vertex_stride = 1;
50 : :
51 : : // Set up the dummy formats, add one for each possible format type that we
52 : : // can represent on the host
53 : : PL_ARRAY(pl_fmt) formats = {0};
54 [ + + ]: 12 : for (enum pl_fmt_type type = 1; type < PL_FMT_TYPE_COUNT; type++) {
55 [ + + ]: 50 : for (int comps = 1; comps <= 4; comps++) {
56 [ + + ]: 200 : for (int depth = 8; depth < 128; depth *= 2) {
57 [ + + ]: 160 : if (type == PL_FMT_FLOAT && depth < 16)
58 : : continue;
59 : :
60 : : static const char *cnames[] = {
61 : : [1] = "r",
62 : : [2] = "rg",
63 : : [3] = "rgb",
64 : : [4] = "rgba",
65 : : };
66 : :
67 : : static const char *tnames[] = {
68 : : [PL_FMT_UNORM] = "",
69 : : [PL_FMT_SNORM] = "s",
70 : : [PL_FMT_UINT] = "u",
71 : : [PL_FMT_SINT] = "i",
72 : : [PL_FMT_FLOAT] = "f",
73 : : };
74 : :
75 : 152 : const char *tname = tnames[type];
76 [ + + ]: 152 : if (type == PL_FMT_FLOAT && depth == 16)
77 : : tname = "hf";
78 : :
79 : 152 : struct pl_fmt_t *fmt = pl_alloc_ptr(gpu, fmt);
80 : 152 : *fmt = (struct pl_fmt_t) {
81 : 152 : .name = pl_asprintf(fmt, "%s%d%s", cnames[comps], depth, tname),
82 : : .type = type,
83 : : .num_components = comps,
84 : : .opaque = false,
85 : : .gatherable = true,
86 : 152 : .internal_size = comps * depth / 8,
87 : : .texel_size = comps * depth / 8,
88 : : .texel_align = 1,
89 : : .caps = PL_FMT_CAP_SAMPLEABLE | PL_FMT_CAP_LINEAR |
90 : : PL_FMT_CAP_RENDERABLE | PL_FMT_CAP_BLENDABLE |
91 : : PL_FMT_CAP_VERTEX | PL_FMT_CAP_HOST_READABLE,
92 : : };
93 : :
94 [ + + ]: 532 : for (int i = 0; i < comps; i++) {
95 : 380 : fmt->component_depth[i] = depth;
96 : 380 : fmt->host_bits[i] = depth;
97 : 380 : fmt->sample_order[i] = i;
98 : : }
99 : :
100 [ + - ]: 152 : if (gpu->glsl.compute)
101 : 152 : fmt->caps |= PL_FMT_CAP_STORABLE;
102 [ + - + - ]: 152 : if (gpu->limits.max_buffer_texels && gpu->limits.max_ubo_size)
103 : 152 : fmt->caps |= PL_FMT_CAP_TEXEL_UNIFORM;
104 [ + - + - ]: 152 : if (gpu->limits.max_buffer_texels && gpu->limits.max_ssbo_size)
105 : 152 : fmt->caps |= PL_FMT_CAP_TEXEL_STORAGE;
106 : :
107 : 152 : fmt->glsl_type = pl_var_glsl_type_name(pl_var_from_fmt(fmt, ""));
108 : 152 : fmt->glsl_format = pl_fmt_glsl_format(fmt, comps);
109 : 152 : fmt->fourcc = pl_fmt_fourcc(fmt);
110 [ + + ]: 152 : if (!fmt->glsl_format)
111 : 80 : fmt->caps &= ~(PL_FMT_CAP_STORABLE | PL_FMT_CAP_TEXEL_STORAGE);
112 [ + + + + : 152 : PL_ARRAY_APPEND(gpu, formats, fmt);
- + ]
113 : : }
114 : : }
115 : : }
116 : :
117 : 2 : gpu->formats = formats.elem;
118 : 2 : gpu->num_formats = formats.num;
119 : 2 : return pl_gpu_finalize(gpu);
120 : : }
121 : :
122 : 2 : static void dumb_destroy(pl_gpu gpu)
123 : : {
124 : 2 : pl_free((void *) gpu);
125 : 2 : }
126 : :
127 : 2 : void pl_gpu_dummy_destroy(pl_gpu *gpu)
128 : : {
129 : 2 : pl_gpu_destroy(*gpu);
130 : 2 : *gpu = NULL;
131 : 2 : }
132 : :
133 : : struct buf_priv {
134 : : uint8_t *data;
135 : : };
136 : :
137 : 5 : static pl_buf dumb_buf_create(pl_gpu gpu, const struct pl_buf_params *params)
138 : : {
139 : 5 : struct pl_buf_t *buf = pl_zalloc_obj(NULL, buf, struct buf_priv);
140 : 5 : buf->params = *params;
141 : 5 : buf->params.initial_data = NULL;
142 : :
143 : 5 : struct buf_priv *p = PL_PRIV(buf);
144 : 5 : p->data = malloc(params->size);
145 [ - + ]: 5 : if (!p->data) {
146 : 0 : PL_ERR(gpu, "Failed allocating memory for dummy buffer!");
147 : 0 : pl_free(buf);
148 : 0 : return NULL;
149 : : }
150 : :
151 [ + + ]: 5 : if (params->initial_data)
152 : : memcpy(p->data, params->initial_data, params->size);
153 [ + + ]: 5 : if (params->host_mapped)
154 : 1 : buf->data = p->data;
155 : :
156 : : return buf;
157 : : }
158 : :
159 : 5 : static void dumb_buf_destroy(pl_gpu gpu, pl_buf buf)
160 : : {
161 : 5 : struct buf_priv *p = PL_PRIV(buf);
162 : 5 : free(p->data);
163 : 5 : pl_free((void *) buf);
164 : 5 : }
165 : :
166 : 0 : uint8_t *pl_buf_dummy_data(pl_buf buf)
167 : : {
168 : 0 : struct buf_priv *p = PL_PRIV(buf);
169 : 0 : return p->data;
170 : : }
171 : :
172 : 1 : static void dumb_buf_write(pl_gpu gpu, pl_buf buf, size_t buf_offset,
173 : : const void *data, size_t size)
174 : : {
175 : 1 : struct buf_priv *p = PL_PRIV(buf);
176 : 1 : memcpy(p->data + buf_offset, data, size);
177 : 1 : }
178 : :
179 : 3 : static bool dumb_buf_read(pl_gpu gpu, pl_buf buf, size_t buf_offset,
180 : : void *dest, size_t size)
181 : : {
182 : 3 : struct buf_priv *p = PL_PRIV(buf);
183 : 3 : memcpy(dest, p->data + buf_offset, size);
184 : 3 : return true;
185 : : }
186 : :
187 : 1 : static void dumb_buf_copy(pl_gpu gpu, pl_buf dst, size_t dst_offset,
188 : : pl_buf src, size_t src_offset, size_t size)
189 : : {
190 : 1 : struct buf_priv *dstp = PL_PRIV(dst);
191 : 1 : struct buf_priv *srcp = PL_PRIV(src);
192 : 1 : memcpy(dstp->data + dst_offset, srcp->data + src_offset, size);
193 : 1 : }
194 : :
195 : : struct tex_priv {
196 : : void *data;
197 : : };
198 : :
199 : : static size_t tex_size(pl_gpu gpu, pl_tex tex)
200 : : {
201 : 460 : size_t size = tex->params.format->texel_size * tex->params.w;
202 : 920 : size *= PL_DEF(tex->params.h, 1);
203 [ + + ]: 460 : size *= PL_DEF(tex->params.d, 1);
204 : : return size;
205 : : }
206 : :
207 : 460 : static pl_tex dumb_tex_create(pl_gpu gpu, const struct pl_tex_params *params)
208 : : {
209 : 460 : struct pl_tex_t *tex = pl_zalloc_obj(NULL, tex, void *);
210 : 460 : tex->params = *params;
211 : 460 : tex->params.initial_data = NULL;
212 : :
213 [ + + ]: 460 : struct tex_priv *p = PL_PRIV(tex);
214 : 460 : p->data = malloc(tex_size(gpu, tex));
215 [ - + ]: 460 : if (!p->data) {
216 : 0 : PL_ERR(gpu, "Failed allocating memory for dummy texture!");
217 : 0 : pl_free(tex);
218 : 0 : return NULL;
219 : : }
220 : :
221 [ + + ]: 460 : if (params->initial_data)
222 : : memcpy(p->data, params->initial_data, tex_size(gpu, tex));
223 : :
224 : : return tex;
225 : : }
226 : :
227 : 1 : pl_tex pl_tex_dummy_create(pl_gpu gpu, const struct pl_tex_dummy_params *params)
228 : : {
229 : : // Only do minimal sanity checking, since this is just a dummy texture
230 [ + - + - : 1 : pl_assert(params->format && params->w >= 0 && params->h >= 0 && params->d >= 0);
+ - - + ]
231 : :
232 : 1 : struct pl_tex_t *tex = pl_zalloc_obj(NULL, tex, struct tex_priv);
233 : 1 : tex->sampler_type = params->sampler_type;
234 : 1 : tex->params = (struct pl_tex_params) {
235 : 1 : .w = params->w,
236 : 1 : .h = params->h,
237 : 1 : .d = params->d,
238 : 1 : .format = params->format,
239 : : .sampleable = true,
240 : 1 : .user_data = params->user_data,
241 : : };
242 : :
243 : 1 : return tex;
244 : : }
245 : :
246 : 461 : static void dumb_tex_destroy(pl_gpu gpu, pl_tex tex)
247 : : {
248 : 461 : struct tex_priv *p = PL_PRIV(tex);
249 [ + + ]: 461 : if (p->data)
250 : 460 : free(p->data);
251 : 461 : pl_free((void *) tex);
252 : 461 : }
253 : :
254 : 2 : uint8_t *pl_tex_dummy_data(pl_tex tex)
255 : : {
256 : 2 : struct tex_priv *p = PL_PRIV(tex);
257 : 2 : return p->data;
258 : : }
259 : :
260 : 228 : static bool dumb_tex_upload(pl_gpu gpu, const struct pl_tex_transfer_params *params)
261 : : {
262 : 228 : pl_tex tex = params->tex;
263 : 228 : struct tex_priv *p = PL_PRIV(tex);
264 [ - + ]: 228 : pl_assert(p->data);
265 : :
266 : 228 : const uint8_t *src = params->ptr;
267 : : uint8_t *dst = p->data;
268 [ - + ]: 228 : if (params->buf) {
269 : 0 : struct buf_priv *bufp = PL_PRIV(params->buf);
270 : 0 : src = (uint8_t *) bufp->data + params->buf_offset;
271 : : }
272 : :
273 : 228 : size_t texel_size = tex->params.format->texel_size;
274 : 228 : size_t row_size = pl_rect_w(params->rc) * texel_size;
275 [ + + ]: 1596 : for (int z = params->rc.z0; z < params->rc.z1; z++) {
276 : 1368 : size_t src_plane = z * params->depth_pitch;
277 : 1368 : size_t dst_plane = z * tex->params.h * tex->params.w * texel_size;
278 [ + + ]: 22116 : for (int y = params->rc.y0; y < params->rc.y1; y++) {
279 : 20748 : size_t src_row = src_plane + y * params->row_pitch;
280 : 20748 : size_t dst_row = dst_plane + y * tex->params.w * texel_size;
281 : 20748 : size_t pos = params->rc.x0 * texel_size;
282 : 20748 : memcpy(&dst[dst_row + pos], &src[src_row + pos], row_size);
283 : : }
284 : : }
285 : :
286 : 228 : return true;
287 : : }
288 : :
289 : 228 : static bool dumb_tex_download(pl_gpu gpu, const struct pl_tex_transfer_params *params)
290 : : {
291 : 228 : pl_tex tex = params->tex;
292 : 228 : struct tex_priv *p = PL_PRIV(tex);
293 [ - + ]: 228 : pl_assert(p->data);
294 : :
295 : : const uint8_t *src = p->data;
296 : 228 : uint8_t *dst = params->ptr;
297 [ - + ]: 228 : if (params->buf) {
298 : 0 : struct buf_priv *bufp = PL_PRIV(params->buf);
299 : 0 : dst = (uint8_t *) bufp->data + params->buf_offset;
300 : : }
301 : :
302 : 228 : size_t texel_size = tex->params.format->texel_size;
303 : 228 : size_t row_size = pl_rect_w(params->rc) * texel_size;
304 [ + + ]: 1596 : for (int z = params->rc.z0; z < params->rc.z1; z++) {
305 : 1368 : size_t src_plane = z * tex->params.h * tex->params.w * texel_size;
306 : 1368 : size_t dst_plane = z * params->depth_pitch;
307 [ + + ]: 22116 : for (int y = params->rc.y0; y < params->rc.y1; y++) {
308 : 20748 : size_t src_row = src_plane + y * tex->params.w * texel_size;
309 : 20748 : size_t dst_row = dst_plane + y * params->row_pitch;
310 : 20748 : size_t pos = params->rc.x0 * texel_size;
311 : 20748 : memcpy(&dst[dst_row + pos], &src[src_row + pos], row_size);
312 : : }
313 : : }
314 : :
315 : 228 : return true;
316 : : }
317 : :
318 : 0 : static int dumb_desc_namespace(pl_gpu gpu, enum pl_desc_type type)
319 : : {
320 : 0 : return 0; // safest behavior: never alias bindings
321 : : }
322 : :
323 : 0 : static pl_pass dumb_pass_create(pl_gpu gpu, const struct pl_pass_params *params)
324 : : {
325 : 0 : PL_ERR(gpu, "Creating render passes is not supported for dummy GPUs");
326 : 0 : return NULL;
327 : : }
328 : :
329 : 228 : static void dumb_gpu_finish(pl_gpu gpu)
330 : : {
331 : : // no-op
332 : 228 : }
333 : :
334 : : static const struct pl_gpu_fns pl_fns_dummy = {
335 : : .destroy = dumb_destroy,
336 : : .buf_create = dumb_buf_create,
337 : : .buf_destroy = dumb_buf_destroy,
338 : : .buf_write = dumb_buf_write,
339 : : .buf_read = dumb_buf_read,
340 : : .buf_copy = dumb_buf_copy,
341 : : .tex_create = dumb_tex_create,
342 : : .tex_destroy = dumb_tex_destroy,
343 : : .tex_upload = dumb_tex_upload,
344 : : .tex_download = dumb_tex_download,
345 : : .desc_namespace = dumb_desc_namespace,
346 : : .pass_create = dumb_pass_create,
347 : : .gpu_finish = dumb_gpu_finish,
348 : : };
|