1 /**************************************************************************
2 *
3 * Copyright (C) 2014 Red Hat Inc.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included
13 * in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 * OTHER DEALINGS IN THE SOFTWARE.
22 *
23 **************************************************************************/
24
25 /* gallium blitter implementation in GL */
26 /* for when we can't use glBlitFramebuffer */
27
28 #include <stdio.h>
29
30 #include "util/u_memory.h"
31 #include "util/u_format.h"
32 #include "util/u_texture.h"
33
34 #include "vrend_shader.h"
35 #include "vrend_renderer.h"
36 #include "vrend_blitter.h"
37
38 #define DEST_SWIZZLE_SNIPPET_SIZE 64
39
40 #define BLIT_USE_GLES (1 << 0)
41 #define BLIT_USE_MSAA (1 << 1)
42 #define BLIT_USE_DEPTH (1 << 2)
43
44 struct vrend_blitter_ctx {
45 virgl_gl_context gl_context;
46 bool initialised;
47 bool use_gles;
48
49 GLuint vaoid;
50
51 GLuint vs;
52 GLuint fs_texfetch_col[PIPE_MAX_TEXTURE_TYPES];
53 GLuint fs_texfetch_depth[PIPE_MAX_TEXTURE_TYPES];
54 GLuint fs_texfetch_depth_msaa[PIPE_MAX_TEXTURE_TYPES];
55 GLuint fs_texfetch_col_swizzle;
56 GLuint fb_id;
57
58 // Parameters related to the creation of fs_texfetch_col_swizzle
59 unsigned fs_texfetch_col_swizzle_nr_samples;
60 bool fs_texfetch_col_swizzle_has_swizzle;
61
62 unsigned dst_width;
63 unsigned dst_height;
64
65 GLuint vbo_id;
66 GLfloat vertices[4][2][4]; /**< {pos, color} or {pos, texcoord} */
67 };
68
69 static struct vrend_blitter_ctx vrend_blit_ctx;
70
71 struct vrend_blitter_point {
72 int x;
73 int y;
74 };
75
76 struct vrend_blitter_delta {
77 int dx;
78 int dy;
79 };
80
81 struct swizzle_and_type {
82 char *twm;
83 char *ivec;
84 bool is_array;
85 };
86
build_and_check(GLenum shader_type,const char * buf)87 static GLint build_and_check(GLenum shader_type, const char *buf)
88 {
89 GLint param;
90 GLint id = glCreateShader(shader_type);
91 glShaderSource(id, 1, (const char **)&buf, NULL);
92 glCompileShader(id);
93
94 glGetShaderiv(id, GL_COMPILE_STATUS, ¶m);
95 if (param == GL_FALSE) {
96 char infolog[65536];
97 int len;
98 glGetShaderInfoLog(id, 65536, &len, infolog);
99 vrend_printf("shader failed to compile\n%s\n", infolog);
100 vrend_printf("GLSL:\n%s\n", buf);
101 glDeleteShader(id);
102 return 0;
103 }
104 return id;
105 }
106
link_and_check(GLuint prog_id)107 static bool link_and_check(GLuint prog_id)
108 {
109 GLint lret;
110
111 glLinkProgram(prog_id);
112 glGetProgramiv(prog_id, GL_LINK_STATUS, &lret);
113 if (lret == GL_FALSE) {
114 char infolog[65536];
115 int len;
116 glGetProgramInfoLog(prog_id, 65536, &len, infolog);
117 vrend_printf("got error linking\n%s\n", infolog);
118 /* dump shaders */
119 glDeleteProgram(prog_id);
120 return false;
121 }
122 return true;
123 }
124
create_dest_swizzle_snippet(const uint8_t swizzle[4],char snippet[DEST_SWIZZLE_SNIPPET_SIZE])125 static void create_dest_swizzle_snippet(const uint8_t swizzle[4],
126 char snippet[DEST_SWIZZLE_SNIPPET_SIZE])
127 {
128 static const uint8_t invalid_swizzle = 0xff;
129 ssize_t si = 0;
130 uint8_t inverse[4] = {invalid_swizzle, invalid_swizzle, invalid_swizzle,
131 invalid_swizzle};
132
133 for (int i = 0; i < 4; ++i) {
134 if (swizzle[i] > 3) continue;
135 if (inverse[swizzle[i]] == invalid_swizzle)
136 inverse[swizzle[i]] = i;
137 }
138
139 for (int i = 0; i < 4; ++i) {
140 int res = -1;
141 if (inverse[i] > 3) {
142 /* Use 0.0f for unused color values, 1.0f for an unused alpha value */
143 res = snprintf(&snippet[si], DEST_SWIZZLE_SNIPPET_SIZE - si,
144 i < 3 ? "0.0f, " : "1.0f");
145 } else {
146 res = snprintf(&snippet[si], DEST_SWIZZLE_SNIPPET_SIZE - si,
147 "texel.%c%s", "rgba"[inverse[i]], i < 3 ? ", " : "");
148 }
149 si += res > 0 ? res : 0;
150 }
151 }
152
vec4_type_for_tgsi_ret(enum tgsi_return_type tgsi_ret)153 static const char *vec4_type_for_tgsi_ret(enum tgsi_return_type tgsi_ret)
154 {
155 switch (tgsi_ret) {
156 case TGSI_RETURN_TYPE_SINT: return "ivec4";
157 case TGSI_RETURN_TYPE_UINT: return "uvec4";
158 default: return "vec4";
159 }
160 }
161
tgsi_ret_for_format(enum virgl_formats format)162 static enum tgsi_return_type tgsi_ret_for_format(enum virgl_formats format)
163 {
164 if (util_format_is_pure_uint(format))
165 return TGSI_RETURN_TYPE_UINT;
166 else if (util_format_is_pure_sint(format))
167 return TGSI_RETURN_TYPE_SINT;
168
169 return TGSI_RETURN_TYPE_UNORM;
170 }
171
get_swizzle(int tgsi_tex_target,unsigned flags,struct swizzle_and_type * retval)172 static void get_swizzle(int tgsi_tex_target, unsigned flags,
173 struct swizzle_and_type *retval)
174 {
175 retval->twm = "";
176 retval->ivec = "";
177 retval->is_array = false;
178 switch (tgsi_tex_target) {
179 case TGSI_TEXTURE_1D:
180 if (flags & (BLIT_USE_GLES | BLIT_USE_DEPTH)) {
181 retval->twm = ".xy";
182 break;
183 }
184 /* fallthrough */
185 case TGSI_TEXTURE_BUFFER:
186 retval->twm = ".x";
187 break;
188 case TGSI_TEXTURE_2D_MSAA:
189 if (flags & BLIT_USE_MSAA) {
190 retval->ivec = "ivec2";
191 }
192 /* fallthrough */
193 case TGSI_TEXTURE_1D_ARRAY:
194 case TGSI_TEXTURE_2D:
195 case TGSI_TEXTURE_RECT:
196 retval->twm = ".xy";
197 break;
198 case TGSI_TEXTURE_2D_ARRAY_MSAA:
199 if (flags & BLIT_USE_MSAA) {
200 retval->ivec = "ivec3";
201 retval->is_array = true;
202 }
203 /* fallthrough */
204 case TGSI_TEXTURE_SHADOW1D:
205 case TGSI_TEXTURE_SHADOW2D:
206 case TGSI_TEXTURE_SHADOW1D_ARRAY:
207 case TGSI_TEXTURE_SHADOWRECT:
208 case TGSI_TEXTURE_3D:
209 case TGSI_TEXTURE_CUBE:
210 case TGSI_TEXTURE_2D_ARRAY:
211 retval->twm = ".xyz";
212 break;
213 case TGSI_TEXTURE_SHADOWCUBE:
214 case TGSI_TEXTURE_SHADOW2D_ARRAY:
215 case TGSI_TEXTURE_SHADOWCUBE_ARRAY:
216 case TGSI_TEXTURE_CUBE_ARRAY:
217 retval->twm = "";
218 break;
219 default:
220 if (flags & BLIT_USE_MSAA) {
221 break;
222 }
223 retval->twm = ".xy";
224 break;
225 }
226 }
227
blit_build_frag_tex_col(struct vrend_blitter_ctx * blit_ctx,int tgsi_tex_target,enum tgsi_return_type tgsi_ret,const uint8_t swizzle[4],int nr_samples)228 static GLuint blit_build_frag_tex_col(struct vrend_blitter_ctx *blit_ctx,
229 int tgsi_tex_target,
230 enum tgsi_return_type tgsi_ret,
231 const uint8_t swizzle[4],
232 int nr_samples)
233 {
234 char shader_buf[4096];
235 struct swizzle_and_type retval;
236 unsigned flags = 0;
237 char dest_swizzle_snippet[DEST_SWIZZLE_SNIPPET_SIZE] = "texel";
238 const char *ext_str = "";
239 bool msaa = nr_samples > 0;
240
241 if (msaa && !blit_ctx->use_gles)
242 ext_str = "#extension GL_ARB_texture_multisample : enable\n";
243 else if (tgsi_tex_target == TGSI_TEXTURE_CUBE_ARRAY ||
244 tgsi_tex_target == TGSI_TEXTURE_SHADOWCUBE_ARRAY)
245 ext_str = "#extension GL_ARB_texture_cube_map_array : require\n";
246
247 if (blit_ctx->use_gles)
248 flags |= BLIT_USE_GLES;
249 if (msaa)
250 flags |= BLIT_USE_MSAA;
251 get_swizzle(tgsi_tex_target, flags, &retval);
252
253 if (swizzle)
254 create_dest_swizzle_snippet(swizzle, dest_swizzle_snippet);
255
256 if (msaa)
257 snprintf(shader_buf, 4096, blit_ctx->use_gles ?
258 (retval.is_array ? FS_TEXFETCH_COL_MSAA_ARRAY_GLES
259 : FS_TEXFETCH_COL_MSAA_GLES)
260 : FS_TEXFETCH_COL_MSAA_GL,
261 ext_str, vec4_type_for_tgsi_ret(tgsi_ret),
262 vrend_shader_samplerreturnconv(tgsi_ret),
263 vrend_shader_samplertypeconv(blit_ctx->use_gles, tgsi_tex_target),
264 nr_samples, retval.ivec, retval.twm, dest_swizzle_snippet);
265 else
266 snprintf(shader_buf, 4096, blit_ctx->use_gles ?
267 (tgsi_tex_target == TGSI_TEXTURE_1D ?
268 FS_TEXFETCH_COL_GLES_1D : FS_TEXFETCH_COL_GLES)
269 : FS_TEXFETCH_COL_GL,
270 ext_str, vec4_type_for_tgsi_ret(tgsi_ret),
271 vrend_shader_samplerreturnconv(tgsi_ret),
272 vrend_shader_samplertypeconv(blit_ctx->use_gles, tgsi_tex_target),
273 retval.twm, dest_swizzle_snippet);
274
275 VREND_DEBUG(dbg_blit, NULL, "-- Blit FS shader MSAA: %d -----------------\n"
276 "%s\n---------------------------------------\n", msaa, shader_buf);
277
278 return build_and_check(GL_FRAGMENT_SHADER, shader_buf);
279 }
280
blit_build_frag_depth(struct vrend_blitter_ctx * blit_ctx,int tgsi_tex_target,bool msaa)281 static GLuint blit_build_frag_depth(struct vrend_blitter_ctx *blit_ctx, int tgsi_tex_target, bool msaa)
282 {
283 char shader_buf[4096];
284 struct swizzle_and_type retval;
285 unsigned flags = BLIT_USE_DEPTH;
286
287 if (msaa)
288 flags |= BLIT_USE_MSAA;
289
290 get_swizzle(tgsi_tex_target, flags, &retval);
291
292 if (msaa)
293 snprintf(shader_buf, 4096, blit_ctx->use_gles ?
294 (retval.is_array ? FS_TEXFETCH_DS_MSAA_ARRAY_GLES : FS_TEXFETCH_DS_MSAA_GLES)
295 : FS_TEXFETCH_DS_MSAA_GL,
296 vrend_shader_samplertypeconv(blit_ctx->use_gles, tgsi_tex_target), retval.ivec, retval.twm);
297 else
298 snprintf(shader_buf, 4096, blit_ctx->use_gles ? FS_TEXFETCH_DS_GLES : FS_TEXFETCH_DS_GL,
299 vrend_shader_samplertypeconv(blit_ctx->use_gles, tgsi_tex_target), retval.twm);
300
301 return build_and_check(GL_FRAGMENT_SHADER, shader_buf);
302 }
303
blit_get_frag_tex_writedepth(struct vrend_blitter_ctx * blit_ctx,int pipe_tex_target,unsigned nr_samples)304 static GLuint blit_get_frag_tex_writedepth(struct vrend_blitter_ctx *blit_ctx, int pipe_tex_target, unsigned nr_samples)
305 {
306 assert(pipe_tex_target < PIPE_MAX_TEXTURE_TYPES);
307
308 GLuint *shader = nr_samples > 0 ? &blit_ctx->fs_texfetch_depth_msaa[pipe_tex_target]
309 : &blit_ctx->fs_texfetch_depth[pipe_tex_target];
310
311 if (!*shader) {
312 unsigned tgsi_tex = util_pipe_tex_to_tgsi_tex(pipe_tex_target, nr_samples);
313 *shader = blit_build_frag_depth(blit_ctx, tgsi_tex, nr_samples > 0);
314 }
315 return *shader;
316 }
317
blit_get_frag_tex_col(struct vrend_blitter_ctx * blit_ctx,int pipe_tex_target,unsigned nr_samples,const struct vrend_format_table * src_entry,const struct vrend_format_table * dst_entry,bool skip_dest_swizzle)318 static GLuint blit_get_frag_tex_col(struct vrend_blitter_ctx *blit_ctx,
319 int pipe_tex_target,
320 unsigned nr_samples,
321 const struct vrend_format_table *src_entry,
322 const struct vrend_format_table *dst_entry,
323 bool skip_dest_swizzle)
324 {
325 assert(pipe_tex_target < PIPE_MAX_TEXTURE_TYPES);
326
327 bool needs_swizzle = !skip_dest_swizzle && (dst_entry->flags & VIRGL_TEXTURE_NEED_SWIZZLE);
328
329
330 GLuint *shader;
331 if (needs_swizzle || nr_samples > 1) {
332 shader = &blit_ctx->fs_texfetch_col_swizzle;
333 if (*shader && (blit_ctx->fs_texfetch_col_swizzle_has_swizzle != needs_swizzle
334 || blit_ctx->fs_texfetch_col_swizzle_nr_samples != nr_samples)) {
335 glDeleteShader(*shader);
336 *shader = 0;
337 }
338 blit_ctx->fs_texfetch_col_swizzle_has_swizzle = needs_swizzle;
339 blit_ctx->fs_texfetch_col_swizzle_nr_samples = nr_samples;
340 } else {
341 shader = &blit_ctx->fs_texfetch_col[pipe_tex_target];
342 }
343
344 if (!*shader) {
345
346 unsigned tgsi_tex = util_pipe_tex_to_tgsi_tex(pipe_tex_target, nr_samples);
347 enum tgsi_return_type tgsi_ret = tgsi_ret_for_format(src_entry->format);
348
349 const uint8_t *swizzle = needs_swizzle ? dst_entry->swizzle : NULL;
350
351 // Integer textures are resolved using just one sample
352 int msaa_samples = nr_samples > 0 ? (tgsi_ret == TGSI_RETURN_TYPE_UNORM ? nr_samples : 1) : 0;
353
354 *shader = blit_build_frag_tex_col(blit_ctx, tgsi_tex, tgsi_ret,
355 swizzle, msaa_samples);
356 }
357 return *shader;
358 }
359
vrend_renderer_init_blit_ctx(struct vrend_blitter_ctx * blit_ctx)360 static void vrend_renderer_init_blit_ctx(struct vrend_blitter_ctx *blit_ctx)
361 {
362 struct virgl_gl_ctx_param ctx_params;
363 int i;
364 if (blit_ctx->initialised) {
365 vrend_sync_make_current(blit_ctx->gl_context);
366 return;
367 }
368
369 blit_ctx->initialised = true;
370 blit_ctx->use_gles = epoxy_is_desktop_gl() == 0;
371 ctx_params.shared = true;
372 for (uint32_t i = 0; i < ARRAY_SIZE(gl_versions); i++) {
373 ctx_params.major_ver = gl_versions[i].major;
374 ctx_params.minor_ver = gl_versions[i].minor;
375
376 blit_ctx->gl_context = vrend_clicbs->create_gl_context(0, &ctx_params);
377 if (blit_ctx->gl_context)
378 break;
379 }
380
381 vrend_sync_make_current(blit_ctx->gl_context);
382 glGenVertexArrays(1, &blit_ctx->vaoid);
383 glGenFramebuffers(1, &blit_ctx->fb_id);
384
385 glGenBuffers(1, &blit_ctx->vbo_id);
386 blit_ctx->vs = build_and_check(GL_VERTEX_SHADER,
387 blit_ctx->use_gles ? VS_PASSTHROUGH_GLES : VS_PASSTHROUGH_GL);
388
389 for (i = 0; i < 4; i++)
390 blit_ctx->vertices[i][0][3] = 1; /*v.w*/
391 glBindVertexArray(blit_ctx->vaoid);
392 glBindBuffer(GL_ARRAY_BUFFER, blit_ctx->vbo_id);
393
394 if (!blit_ctx->use_gles)
395 glEnable(GL_FRAMEBUFFER_SRGB);
396 }
397
blitter_set_rectangle(struct vrend_blitter_ctx * blit_ctx,int x1,int y1,int x2,int y2,float depth)398 static void blitter_set_rectangle(struct vrend_blitter_ctx *blit_ctx,
399 int x1, int y1, int x2, int y2,
400 float depth)
401 {
402 int i;
403
404 /* set vertex positions */
405 blit_ctx->vertices[0][0][0] = (float)x1 / blit_ctx->dst_width * 2.0f - 1.0f; /*v0.x*/
406 blit_ctx->vertices[0][0][1] = (float)y1 / blit_ctx->dst_height * 2.0f - 1.0f; /*v0.y*/
407
408 blit_ctx->vertices[1][0][0] = (float)x2 / blit_ctx->dst_width * 2.0f - 1.0f; /*v1.x*/
409 blit_ctx->vertices[1][0][1] = (float)y1 / blit_ctx->dst_height * 2.0f - 1.0f; /*v1.y*/
410
411 blit_ctx->vertices[2][0][0] = (float)x2 / blit_ctx->dst_width * 2.0f - 1.0f; /*v2.x*/
412 blit_ctx->vertices[2][0][1] = (float)y2 / blit_ctx->dst_height * 2.0f - 1.0f; /*v2.y*/
413
414 blit_ctx->vertices[3][0][0] = (float)x1 / blit_ctx->dst_width * 2.0f - 1.0f; /*v3.x*/
415 blit_ctx->vertices[3][0][1] = (float)y2 / blit_ctx->dst_height * 2.0f - 1.0f; /*v3.y*/
416
417 for (i = 0; i < 4; i++)
418 blit_ctx->vertices[i][0][2] = depth; /*z*/
419
420 glViewport(0, 0, blit_ctx->dst_width, blit_ctx->dst_height);
421 }
422
get_texcoords(struct vrend_blitter_ctx * blit_ctx,struct vrend_resource * src_res,int src_level,int x1,int y1,int x2,int y2,float out[4])423 static void get_texcoords(struct vrend_blitter_ctx *blit_ctx,
424 struct vrend_resource *src_res,
425 int src_level,
426 int x1, int y1, int x2, int y2,
427 float out[4])
428 {
429 bool normalized = (src_res->base.target != PIPE_TEXTURE_RECT || blit_ctx->use_gles) &&
430 src_res->base.nr_samples < 1;
431
432 if (normalized) {
433 out[0] = x1 / (float)u_minify(src_res->base.width0, src_level);
434 out[1] = y1 / (float)u_minify(src_res->base.height0, src_level);
435 out[2] = x2 / (float)u_minify(src_res->base.width0, src_level);
436 out[3] = y2 / (float)u_minify(src_res->base.height0, src_level);
437 } else {
438 out[0] = (float) x1;
439 out[1] = (float) y1;
440 out[2] = (float) x2;
441 out[3] = (float) y2;
442 }
443 }
444
set_texcoords_in_vertices(const float coord[4],float * out,unsigned stride)445 static void set_texcoords_in_vertices(const float coord[4],
446 float *out, unsigned stride)
447 {
448 out[0] = coord[0]; /*t0.s*/
449 out[1] = coord[1]; /*t0.t*/
450 out += stride;
451 out[0] = coord[2]; /*t1.s*/
452 out[1] = coord[1]; /*t1.t*/
453 out += stride;
454 out[0] = coord[2]; /*t2.s*/
455 out[1] = coord[3]; /*t2.t*/
456 out += stride;
457 out[0] = coord[0]; /*t3.s*/
458 out[1] = coord[3]; /*t3.t*/
459 }
460
blitter_set_texcoords(struct vrend_blitter_ctx * blit_ctx,struct vrend_resource * src_res,int level,float layer,unsigned sample,int x1,int y1,int x2,int y2)461 static void blitter_set_texcoords(struct vrend_blitter_ctx *blit_ctx,
462 struct vrend_resource *src_res,
463 int level,
464 float layer, unsigned sample,
465 int x1, int y1, int x2, int y2)
466 {
467 float coord[4];
468 float face_coord[4][2];
469 int i;
470 get_texcoords(blit_ctx, src_res, level, x1, y1, x2, y2, coord);
471
472 if (src_res->base.target == PIPE_TEXTURE_CUBE ||
473 src_res->base.target == PIPE_TEXTURE_CUBE_ARRAY) {
474 set_texcoords_in_vertices(coord, &face_coord[0][0], 2);
475 util_map_texcoords2d_onto_cubemap((unsigned)layer % 6,
476 /* pointer, stride in floats */
477 &face_coord[0][0], 2,
478 &blit_ctx->vertices[0][1][0], 8,
479 FALSE);
480 } else {
481 set_texcoords_in_vertices(coord, &blit_ctx->vertices[0][1][0], 8);
482 }
483
484 switch (src_res->base.target) {
485 case PIPE_TEXTURE_3D:
486 {
487 float r = layer / (float)u_minify(src_res->base.depth0,
488 level);
489 for (i = 0; i < 4; i++)
490 blit_ctx->vertices[i][1][2] = r; /*r*/
491 }
492 break;
493
494 case PIPE_TEXTURE_1D_ARRAY:
495 for (i = 0; i < 4; i++)
496 blit_ctx->vertices[i][1][1] = (float) layer; /*t*/
497 break;
498
499 case PIPE_TEXTURE_2D_ARRAY:
500 for (i = 0; i < 4; i++) {
501 blit_ctx->vertices[i][1][2] = (float) layer; /*r*/
502 blit_ctx->vertices[i][1][3] = (float) sample; /*q*/
503 }
504 break;
505 case PIPE_TEXTURE_CUBE_ARRAY:
506 for (i = 0; i < 4; i++)
507 blit_ctx->vertices[i][1][3] = (float) ((unsigned)layer / 6); /*w*/
508 break;
509 case PIPE_TEXTURE_2D:
510 for (i = 0; i < 4; i++) {
511 blit_ctx->vertices[i][1][3] = (float) sample; /*r*/
512 }
513 break;
514 default:;
515 }
516 }
517 #if 0
518 static void set_dsa_keep_depth_stencil(void)
519 {
520 glDisable(GL_STENCIL_TEST);
521 glDisable(GL_DEPTH_TEST);
522 glDepthMask(GL_FALSE);
523 }
524 #endif
525
set_dsa_write_depth_keep_stencil(void)526 static void set_dsa_write_depth_keep_stencil(void)
527 {
528 glDisable(GL_STENCIL_TEST);
529 glEnable(GL_DEPTH_TEST);
530 glDepthFunc(GL_ALWAYS);
531 glDepthMask(GL_TRUE);
532 }
533
to_gl_swizzle(int swizzle)534 static inline GLenum to_gl_swizzle(int swizzle)
535 {
536 switch (swizzle) {
537 case PIPE_SWIZZLE_RED: return GL_RED;
538 case PIPE_SWIZZLE_GREEN: return GL_GREEN;
539 case PIPE_SWIZZLE_BLUE: return GL_BLUE;
540 case PIPE_SWIZZLE_ALPHA: return GL_ALPHA;
541 case PIPE_SWIZZLE_ZERO: return GL_ZERO;
542 case PIPE_SWIZZLE_ONE: return GL_ONE;
543 default:
544 assert(0);
545 return 0;
546 }
547 }
548
549 /* Calculate the delta required to keep 'v' within [0, max] */
calc_delta_for_bound(int v,int max)550 static int calc_delta_for_bound(int v, int max)
551 {
552 int delta = 0;
553
554 if (v < 0)
555 delta = -v;
556 else if (v > max)
557 delta = - (v - max);
558
559 return delta;
560 }
561
562 /* Calculate the deltas for the source blit region points in order to bound
563 * them within the source resource extents */
calc_src_deltas_for_bounds(struct vrend_resource * src_res,const struct pipe_blit_info * info,struct vrend_blitter_delta * src0_delta,struct vrend_blitter_delta * src1_delta)564 static void calc_src_deltas_for_bounds(struct vrend_resource *src_res,
565 const struct pipe_blit_info *info,
566 struct vrend_blitter_delta *src0_delta,
567 struct vrend_blitter_delta *src1_delta)
568 {
569 int max_x = u_minify(src_res->base.width0, info->src.level) - 1;
570 int max_y = u_minify(src_res->base.height0, info->src.level) - 1;
571
572 /* Whether the bounds for the coordinates of a point are inclusive or
573 * exclusive depends on the direction of the blit read. Adjust the max
574 * bounds accordingly, with an adjustment of 0 for inclusive, and 1 for
575 * exclusive. */
576 int src0_x_excl = info->src.box.width < 0;
577 int src0_y_excl = info->src.box.height < 0;
578
579 src0_delta->dx = calc_delta_for_bound(info->src.box.x, max_x + src0_x_excl);
580 src0_delta->dy = calc_delta_for_bound(info->src.box.y, max_y + src0_y_excl);
581
582 src1_delta->dx = calc_delta_for_bound(info->src.box.x + info->src.box.width,
583 max_x + !src0_x_excl);
584 src1_delta->dy = calc_delta_for_bound(info->src.box.y + info->src.box.height,
585 max_y + !src0_y_excl);
586 }
587
588 /* Calculate dst delta values to adjust the dst points for any changes in the
589 * src points */
calc_dst_deltas_from_src(const struct pipe_blit_info * info,const struct vrend_blitter_delta * src0_delta,const struct vrend_blitter_delta * src1_delta,struct vrend_blitter_delta * dst0_delta,struct vrend_blitter_delta * dst1_delta)590 static void calc_dst_deltas_from_src(const struct pipe_blit_info *info,
591 const struct vrend_blitter_delta *src0_delta,
592 const struct vrend_blitter_delta *src1_delta,
593 struct vrend_blitter_delta *dst0_delta,
594 struct vrend_blitter_delta *dst1_delta)
595 {
596 float scale_x = (float)info->dst.box.width / (float)info->src.box.width;
597 float scale_y = (float)info->dst.box.height / (float)info->src.box.height;
598
599 dst0_delta->dx = src0_delta->dx * scale_x;
600 dst0_delta->dy = src0_delta->dy * scale_y;
601
602 dst1_delta->dx = src1_delta->dx * scale_x;
603 dst1_delta->dy = src1_delta->dy * scale_y;
604 }
605
blitter_set_points(struct vrend_blitter_ctx * blit_ctx,const struct pipe_blit_info * info,struct vrend_resource * src_res,struct vrend_resource * dst_res,struct vrend_blitter_point * src0,struct vrend_blitter_point * src1)606 static void blitter_set_points(struct vrend_blitter_ctx *blit_ctx,
607 const struct pipe_blit_info *info,
608 struct vrend_resource *src_res,
609 struct vrend_resource *dst_res,
610 struct vrend_blitter_point *src0,
611 struct vrend_blitter_point *src1)
612 {
613 struct vrend_blitter_point dst0, dst1;
614 struct vrend_blitter_delta src0_delta, src1_delta, dst0_delta, dst1_delta;
615
616 blit_ctx->dst_width = u_minify(dst_res->base.width0, info->dst.level);
617 blit_ctx->dst_height = u_minify(dst_res->base.height0, info->dst.level);
618
619 /* Calculate src and dst points taking deltas into account */
620 calc_src_deltas_for_bounds(src_res, info, &src0_delta, &src1_delta);
621 calc_dst_deltas_from_src(info, &src0_delta, &src1_delta, &dst0_delta, &dst1_delta);
622
623 src0->x = info->src.box.x + src0_delta.dx;
624 src0->y = info->src.box.y + src0_delta.dy;
625 src1->x = info->src.box.x + info->src.box.width + src1_delta.dx;
626 src1->y = info->src.box.y + info->src.box.height + src1_delta.dy;
627
628 dst0.x = info->dst.box.x + dst0_delta.dx;
629 dst0.y = info->dst.box.y + dst0_delta.dy;
630 dst1.x = info->dst.box.x + info->dst.box.width + dst1_delta.dx;
631 dst1.y = info->dst.box.y + info->dst.box.height + dst1_delta.dy;
632
633 VREND_DEBUG(dbg_blit, NULL, "Blitter src:[%3d, %3d] - [%3d, %3d] to dst:[%3d, %3d] - [%3d, %3d]\n",
634 src0->x, src0->y, src1->x, src1->y,
635 dst0.x, dst0.y, dst1.x, dst1.y);
636
637 blitter_set_rectangle(blit_ctx, dst0.x, dst0.y, dst1.x, dst1.y, 0);
638 }
639
vrend_set_tex_param(struct vrend_resource * src_res,const struct pipe_blit_info * info,bool has_texture_srgb_decode)640 static void vrend_set_tex_param(struct vrend_resource *src_res,
641 const struct pipe_blit_info *info,
642 bool has_texture_srgb_decode)
643 {
644 const struct vrend_format_table *src_entry =
645 vrend_get_format_table_entry_with_emulation(src_res->base.bind, info->src.format);
646
647 if (src_entry->flags & VIRGL_TEXTURE_NEED_SWIZZLE) {
648 glTexParameteri(src_res->target, GL_TEXTURE_SWIZZLE_R,
649 to_gl_swizzle(src_entry->swizzle[0]));
650 glTexParameteri(src_res->target, GL_TEXTURE_SWIZZLE_G,
651 to_gl_swizzle(src_entry->swizzle[1]));
652 glTexParameteri(src_res->target, GL_TEXTURE_SWIZZLE_B,
653 to_gl_swizzle(src_entry->swizzle[2]));
654 glTexParameteri(src_res->target, GL_TEXTURE_SWIZZLE_A,
655 to_gl_swizzle(src_entry->swizzle[3]));
656 }
657
658 /* Just make sure that no stale state disabled decoding */
659 if (has_texture_srgb_decode && util_format_is_srgb(info->src.format) &&
660 src_res->base.nr_samples < 1)
661 glTexParameteri(src_res->target, GL_TEXTURE_SRGB_DECODE_EXT, GL_DECODE_EXT);
662
663 if (src_res->base.nr_samples < 1) {
664 glTexParameteri(src_res->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
665 glTexParameteri(src_res->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
666 glTexParameteri(src_res->target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
667 }
668
669 glTexParameteri(src_res->target, GL_TEXTURE_BASE_LEVEL, info->src.level);
670 glTexParameteri(src_res->target, GL_TEXTURE_MAX_LEVEL, info->src.level);
671
672 if (src_res->base.nr_samples < 1) {
673 GLenum filter = info->filter == PIPE_TEX_FILTER_NEAREST ?
674 GL_NEAREST : GL_LINEAR;
675 glTexParameterf(src_res->target, GL_TEXTURE_MAG_FILTER, filter);
676 glTexParameterf(src_res->target, GL_TEXTURE_MIN_FILTER, filter);
677 }
678 }
679
vrend_set_vertex_param(GLuint prog_id)680 static void vrend_set_vertex_param(GLuint prog_id)
681 {
682 GLuint pos_loc, tc_loc;
683
684 pos_loc = glGetAttribLocation(prog_id, "arg0");
685 tc_loc = glGetAttribLocation(prog_id, "arg1");
686
687 glVertexAttribPointer(pos_loc, 4, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)0);
688 glVertexAttribPointer(tc_loc, 4, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)(4 * sizeof(float)));
689
690 glEnableVertexAttribArray(pos_loc);
691 glEnableVertexAttribArray(tc_loc);
692 }
693
694 /* implement blitting using OpenGL. */
vrend_renderer_blit_gl(MAYBE_UNUSED struct vrend_context * ctx,struct vrend_resource * src_res,struct vrend_resource * dst_res,GLenum blit_views[2],const struct pipe_blit_info * info,bool has_texture_srgb_decode,bool has_srgb_write_control,bool skip_dest_swizzle)695 void vrend_renderer_blit_gl(MAYBE_UNUSED struct vrend_context *ctx,
696 struct vrend_resource *src_res,
697 struct vrend_resource *dst_res,
698 GLenum blit_views[2],
699 const struct pipe_blit_info *info,
700 bool has_texture_srgb_decode,
701 bool has_srgb_write_control,
702 bool skip_dest_swizzle)
703 {
704 struct vrend_blitter_ctx *blit_ctx = &vrend_blit_ctx;
705 GLuint buffers;
706 GLuint prog_id;
707 GLuint fs_id;
708 bool has_depth, has_stencil;
709 bool blit_stencil, blit_depth;
710 int dst_z;
711 struct vrend_blitter_point src0, src1;
712 const struct util_format_description *src_desc =
713 util_format_description(src_res->base.format);
714 const struct util_format_description *dst_desc =
715 util_format_description(dst_res->base.format);
716 const struct vrend_format_table *orig_src_entry = vrend_get_format_table_entry(info->src.format);
717 const struct vrend_format_table *dst_entry =
718 vrend_get_format_table_entry_with_emulation(dst_res->base.bind, info->dst.format);
719
720 has_depth = util_format_has_depth(src_desc) &&
721 util_format_has_depth(dst_desc);
722 has_stencil = util_format_has_stencil(src_desc) &&
723 util_format_has_stencil(dst_desc);
724
725 blit_depth = has_depth && (info->mask & PIPE_MASK_Z);
726 blit_stencil = has_stencil && (info->mask & PIPE_MASK_S) & 0;
727
728 vrend_renderer_init_blit_ctx(blit_ctx);
729 blitter_set_points(blit_ctx, info, src_res, dst_res, &src0, &src1);
730
731 prog_id = glCreateProgram();
732 glAttachShader(prog_id, blit_ctx->vs);
733
734 if (blit_depth || blit_stencil) {
735 fs_id = blit_get_frag_tex_writedepth(blit_ctx, src_res->base.target,
736 src_res->base.nr_samples);
737 } else {
738 fs_id = blit_get_frag_tex_col(blit_ctx, src_res->base.target,
739 src_res->base.nr_samples,
740 orig_src_entry, dst_entry,
741 skip_dest_swizzle);
742 }
743 glAttachShader(prog_id, fs_id);
744
745 if(!link_and_check(prog_id))
746 return;
747
748 glUseProgram(prog_id);
749
750 glBindFramebuffer(GL_FRAMEBUFFER, blit_ctx->fb_id);
751 vrend_fb_bind_texture_id(dst_res, blit_views[1], 0, info->dst.level, info->dst.box.z);
752
753 buffers = GL_COLOR_ATTACHMENT0;
754 glDrawBuffers(1, &buffers);
755
756 glBindTexture(src_res->target, blit_views[0]);
757 vrend_set_tex_param(src_res, info, has_texture_srgb_decode);
758 vrend_set_vertex_param(prog_id);
759
760 set_dsa_write_depth_keep_stencil();
761
762 if (info->scissor_enable) {
763 glScissor(info->scissor.minx, info->scissor.miny, info->scissor.maxx - info->scissor.minx, info->scissor.maxy - info->scissor.miny);
764 glEnable(GL_SCISSOR_TEST);
765 } else
766 glDisable(GL_SCISSOR_TEST);
767
768 if (has_srgb_write_control) {
769 if (util_format_is_srgb(info->dst.format) || util_format_is_srgb(info->src.format)) {
770 VREND_DEBUG(dbg_blit, ctx, "%s: Enable GL_FRAMEBUFFER_SRGB\n", __func__);
771 glEnable(GL_FRAMEBUFFER_SRGB);
772 } else {
773 VREND_DEBUG(dbg_blit, ctx, "%s: Disable GL_FRAMEBUFFER_SRGB\n", __func__);
774 glDisable(GL_FRAMEBUFFER_SRGB);
775 }
776 }
777
778 for (dst_z = 0; dst_z < info->dst.box.depth; dst_z++) {
779 float dst2src_scale = info->src.box.depth / (float)info->dst.box.depth;
780 float dst_offset = ((info->src.box.depth - 1) -
781 (info->dst.box.depth - 1) * dst2src_scale) * 0.5;
782 float src_z = (dst_z + dst_offset) * dst2src_scale;
783 uint32_t layer = (dst_res->target == GL_TEXTURE_CUBE_MAP) ? info->dst.box.z : dst_z;
784
785 glBindFramebuffer(GL_FRAMEBUFFER, blit_ctx->fb_id);
786 vrend_fb_bind_texture_id(dst_res, blit_views[1], 0, info->dst.level, layer);
787
788 buffers = GL_COLOR_ATTACHMENT0;
789 glDrawBuffers(1, &buffers);
790 blitter_set_texcoords(blit_ctx, src_res, info->src.level,
791 info->src.box.z + src_z, 0,
792 src0.x, src0.y, src1.x, src1.y);
793
794 glBufferData(GL_ARRAY_BUFFER, sizeof(blit_ctx->vertices), blit_ctx->vertices, GL_STATIC_DRAW);
795 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
796 }
797
798 glUseProgram(0);
799 glDeleteProgram(prog_id);
800 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
801 GL_TEXTURE_2D, 0, 0);
802 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
803 GL_TEXTURE_2D, 0, 0);
804 glBindTexture(src_res->target, 0);
805 }
806
vrend_blitter_fini(void)807 void vrend_blitter_fini(void)
808 {
809 vrend_blit_ctx.initialised = false;
810 vrend_clicbs->destroy_gl_context(vrend_blit_ctx.gl_context);
811 memset(&vrend_blit_ctx, 0, sizeof(vrend_blit_ctx));
812 }
813