2 * Copyright © 2014-2017 Broadcom
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
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
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24 #include "util/u_blitter.h"
25 #include "util/u_prim.h"
26 #include "util/u_format.h"
27 #include "util/u_pack_color.h"
28 #include "util/u_prim_restart.h"
29 #include "util/u_upload_mgr.h"
30 #include "indices/u_primconvert.h"
32 #include "v3d_context.h"
33 #include "v3d_resource.h"
35 #include "broadcom/compiler/v3d_compiler.h"
36 #include "broadcom/common/v3d_macros.h"
37 #include "broadcom/cle/v3dx_pack.h"
40 * Does the initial bining command list setup for drawing to a given FBO.
43 vc5_start_draw(struct vc5_context
*vc5
)
45 struct vc5_job
*job
= vc5
->job
;
50 /* Get space to emit our BCL state, using a branch to jump to a new BO
53 vc5_cl_ensure_space_with_branch(&job
->bcl
, 256 /* XXX */);
55 job
->submit
.bcl_start
= job
->bcl
.bo
->offset
;
56 vc5_job_add_bo(job
, job
->bcl
.bo
);
58 job
->tile_alloc
= vc5_bo_alloc(vc5
->screen
, 1024 * 1024, "tile alloc");
59 uint32_t tsda_per_tile_size
= vc5
->screen
->devinfo
.ver
>= 40 ? 256 : 64;
60 job
->tile_state
= vc5_bo_alloc(vc5
->screen
,
67 /* "Binning mode lists start with a Tile Binning Mode Configuration
70 * Part1 signals the end of binning config setup.
72 cl_emit(&job
->bcl
, TILE_BINNING_MODE_CONFIGURATION_PART2
, config
) {
73 config
.tile_allocation_memory_address
=
74 cl_address(job
->tile_alloc
, 0);
75 config
.tile_allocation_memory_size
= job
->tile_alloc
->size
;
79 cl_emit(&job
->bcl
, TILE_BINNING_MODE_CONFIGURATION_PART1
, config
) {
81 config
.width_in_pixels_minus_1
= vc5
->framebuffer
.width
- 1;
82 config
.height_in_pixels_minus_1
= vc5
->framebuffer
.height
- 1;
83 config
.number_of_render_targets_minus_1
=
84 MAX2(vc5
->framebuffer
.nr_cbufs
, 1) - 1;
85 #else /* V3D_VERSION < 40 */
86 config
.tile_state_data_array_base_address
=
87 cl_address(job
->tile_state
, 0);
89 config
.width_in_tiles
= job
->draw_tiles_x
;
90 config
.height_in_tiles
= job
->draw_tiles_y
;
92 config
.number_of_render_targets
=
93 MAX2(vc5
->framebuffer
.nr_cbufs
, 1);
94 #endif /* V3D_VERSION < 40 */
96 config
.multisample_mode_4x
= job
->msaa
;
98 config
.maximum_bpp_of_all_render_targets
= job
->internal_bpp
;
101 /* There's definitely nothing in the VCD cache we want. */
102 cl_emit(&job
->bcl
, FLUSH_VCD_CACHE
, bin
);
104 /* Disable any leftover OQ state from another job. */
105 cl_emit(&job
->bcl
, OCCLUSION_QUERY_COUNTER
, counter
);
107 /* "Binning mode lists must have a Start Tile Binning item (6) after
108 * any prefix state data before the binning list proper starts."
110 cl_emit(&job
->bcl
, START_TILE_BINNING
, bin
);
112 job
->needs_flush
= true;
113 job
->draw_width
= vc5
->framebuffer
.width
;
114 job
->draw_height
= vc5
->framebuffer
.height
;
118 vc5_predraw_check_textures(struct pipe_context
*pctx
,
119 struct vc5_texture_stateobj
*stage_tex
)
121 struct vc5_context
*vc5
= vc5_context(pctx
);
123 for (int i
= 0; i
< stage_tex
->num_textures
; i
++) {
124 struct pipe_sampler_view
*view
= stage_tex
->textures
[i
];
128 vc5_flush_jobs_writing_resource(vc5
, view
->texture
);
133 vc5_emit_gl_shader_state(struct vc5_context
*vc5
,
134 const struct pipe_draw_info
*info
)
136 struct vc5_job
*job
= vc5
->job
;
137 /* VC5_DIRTY_VTXSTATE */
138 struct vc5_vertex_stateobj
*vtx
= vc5
->vtx
;
139 /* VC5_DIRTY_VTXBUF */
140 struct vc5_vertexbuf_stateobj
*vertexbuf
= &vc5
->vertexbuf
;
142 /* Upload the uniforms to the indirect CL first */
143 struct vc5_cl_reloc fs_uniforms
=
144 vc5_write_uniforms(vc5
, vc5
->prog
.fs
,
145 &vc5
->constbuf
[PIPE_SHADER_FRAGMENT
],
147 struct vc5_cl_reloc vs_uniforms
=
148 vc5_write_uniforms(vc5
, vc5
->prog
.vs
,
149 &vc5
->constbuf
[PIPE_SHADER_VERTEX
],
151 struct vc5_cl_reloc cs_uniforms
=
152 vc5_write_uniforms(vc5
, vc5
->prog
.cs
,
153 &vc5
->constbuf
[PIPE_SHADER_VERTEX
],
156 /* See GFXH-930 workaround below */
157 uint32_t num_elements_to_emit
= MAX2(vtx
->num_elements
, 1);
158 uint32_t shader_rec_offset
=
159 vc5_cl_ensure_space(&job
->indirect
,
160 cl_packet_length(GL_SHADER_STATE_RECORD
) +
161 num_elements_to_emit
*
162 cl_packet_length(GL_SHADER_STATE_ATTRIBUTE_RECORD
),
165 cl_emit(&job
->indirect
, GL_SHADER_STATE_RECORD
, shader
) {
166 shader
.enable_clipping
= true;
167 /* VC5_DIRTY_PRIM_MODE | VC5_DIRTY_RASTERIZER */
168 shader
.point_size_in_shaded_vertex_data
=
169 (info
->mode
== PIPE_PRIM_POINTS
&&
170 vc5
->rasterizer
->base
.point_size_per_vertex
);
172 /* Must be set if the shader modifies Z, discards, or modifies
173 * the sample mask. For any of these cases, the fragment
174 * shader needs to write the Z value (even just discards).
176 shader
.fragment_shader_does_z_writes
=
177 (vc5
->prog
.fs
->prog_data
.fs
->writes_z
||
178 vc5
->prog
.fs
->prog_data
.fs
->discard
);
180 shader
.fragment_shader_uses_real_pixel_centre_w_in_addition_to_centroid_w2
=
181 vc5
->prog
.fs
->prog_data
.fs
->uses_centroid_and_center_w
;
183 shader
.number_of_varyings_in_fragment_shader
=
184 vc5
->prog
.fs
->prog_data
.base
->num_inputs
;
186 shader
.propagate_nans
= true;
188 shader
.coordinate_shader_code_address
=
189 cl_address(vc5
->prog
.cs
->bo
, 0);
190 shader
.vertex_shader_code_address
=
191 cl_address(vc5
->prog
.vs
->bo
, 0);
192 shader
.fragment_shader_code_address
=
193 cl_address(vc5
->prog
.fs
->bo
, 0);
195 /* XXX: Use combined input/output size flag in the common
198 shader
.coordinate_shader_has_separate_input_and_output_vpm_blocks
= true;
199 shader
.vertex_shader_has_separate_input_and_output_vpm_blocks
= true;
200 shader
.coordinate_shader_input_vpm_segment_size
=
201 MAX2(vc5
->prog
.cs
->prog_data
.vs
->vpm_input_size
, 1);
202 shader
.vertex_shader_input_vpm_segment_size
=
203 MAX2(vc5
->prog
.vs
->prog_data
.vs
->vpm_input_size
, 1);
205 shader
.coordinate_shader_output_vpm_segment_size
=
206 vc5
->prog
.cs
->prog_data
.vs
->vpm_output_size
;
207 shader
.vertex_shader_output_vpm_segment_size
=
208 vc5
->prog
.vs
->prog_data
.vs
->vpm_output_size
;
210 shader
.coordinate_shader_uniforms_address
= cs_uniforms
;
211 shader
.vertex_shader_uniforms_address
= vs_uniforms
;
212 shader
.fragment_shader_uniforms_address
= fs_uniforms
;
214 #if V3D_VERSION >= 41
215 shader
.coordinate_shader_4_way_threadable
=
216 vc5
->prog
.cs
->prog_data
.vs
->base
.threads
== 4;
217 shader
.vertex_shader_4_way_threadable
=
218 vc5
->prog
.vs
->prog_data
.vs
->base
.threads
== 4;
219 shader
.fragment_shader_4_way_threadable
=
220 vc5
->prog
.fs
->prog_data
.fs
->base
.threads
== 4;
222 shader
.coordinate_shader_start_in_final_thread_section
=
223 vc5
->prog
.cs
->prog_data
.vs
->base
.single_seg
;
224 shader
.vertex_shader_start_in_final_thread_section
=
225 vc5
->prog
.vs
->prog_data
.vs
->base
.single_seg
;
226 shader
.fragment_shader_start_in_final_thread_section
=
227 vc5
->prog
.fs
->prog_data
.fs
->base
.single_seg
;
229 shader
.coordinate_shader_4_way_threadable
=
230 vc5
->prog
.cs
->prog_data
.vs
->base
.threads
== 4;
231 shader
.coordinate_shader_2_way_threadable
=
232 vc5
->prog
.cs
->prog_data
.vs
->base
.threads
== 2;
233 shader
.vertex_shader_4_way_threadable
=
234 vc5
->prog
.vs
->prog_data
.vs
->base
.threads
== 4;
235 shader
.vertex_shader_2_way_threadable
=
236 vc5
->prog
.vs
->prog_data
.vs
->base
.threads
== 2;
237 shader
.fragment_shader_4_way_threadable
=
238 vc5
->prog
.fs
->prog_data
.fs
->base
.threads
== 4;
239 shader
.fragment_shader_2_way_threadable
=
240 vc5
->prog
.fs
->prog_data
.fs
->base
.threads
== 2;
243 shader
.vertex_id_read_by_coordinate_shader
=
244 vc5
->prog
.cs
->prog_data
.vs
->uses_vid
;
245 shader
.instance_id_read_by_coordinate_shader
=
246 vc5
->prog
.cs
->prog_data
.vs
->uses_iid
;
247 shader
.vertex_id_read_by_vertex_shader
=
248 vc5
->prog
.vs
->prog_data
.vs
->uses_vid
;
249 shader
.instance_id_read_by_vertex_shader
=
250 vc5
->prog
.vs
->prog_data
.vs
->uses_iid
;
252 shader
.address_of_default_attribute_values
=
253 cl_address(vtx
->default_attribute_values
, 0);
256 for (int i
= 0; i
< vtx
->num_elements
; i
++) {
257 struct pipe_vertex_element
*elem
= &vtx
->pipe
[i
];
258 struct pipe_vertex_buffer
*vb
=
259 &vertexbuf
->vb
[elem
->vertex_buffer_index
];
260 struct vc5_resource
*rsc
= vc5_resource(vb
->buffer
.resource
);
262 const uint32_t size
=
263 cl_packet_length(GL_SHADER_STATE_ATTRIBUTE_RECORD
);
264 cl_emit_with_prepacked(&job
->indirect
,
265 GL_SHADER_STATE_ATTRIBUTE_RECORD
,
266 &vtx
->attrs
[i
* size
], attr
) {
267 attr
.stride
= vb
->stride
;
268 attr
.address
= cl_address(rsc
->bo
,
271 attr
.number_of_values_read_by_coordinate_shader
=
272 vc5
->prog
.cs
->prog_data
.vs
->vattr_sizes
[i
];
273 attr
.number_of_values_read_by_vertex_shader
=
274 vc5
->prog
.vs
->prog_data
.vs
->vattr_sizes
[i
];
275 #if V3D_VERSION >= 41
276 attr
.maximum_index
= 0xffffff;
281 if (vtx
->num_elements
== 0) {
282 /* GFXH-930: At least one attribute must be enabled and read
283 * by CS and VS. If we have no attributes being consumed by
284 * the shader, set up a dummy to be loaded into the VPM.
286 cl_emit(&job
->indirect
, GL_SHADER_STATE_ATTRIBUTE_RECORD
, attr
) {
287 /* Valid address of data whose value will be unused. */
288 attr
.address
= cl_address(job
->indirect
.bo
, 0);
290 attr
.type
= ATTRIBUTE_FLOAT
;
294 attr
.number_of_values_read_by_coordinate_shader
= 1;
295 attr
.number_of_values_read_by_vertex_shader
= 1;
299 cl_emit(&job
->bcl
, GL_SHADER_STATE
, state
) {
300 state
.address
= cl_address(job
->indirect
.bo
, shader_rec_offset
);
301 state
.number_of_attribute_arrays
= num_elements_to_emit
;
304 vc5_bo_unreference(&cs_uniforms
.bo
);
305 vc5_bo_unreference(&vs_uniforms
.bo
);
306 vc5_bo_unreference(&fs_uniforms
.bo
);
308 job
->shader_rec_count
++;
312 * Computes the various transform feedback statistics, since they can't be
313 * recorded by CL packets.
316 vc5_tf_statistics_record(struct vc5_context
*vc5
,
317 const struct pipe_draw_info
*info
,
320 if (!vc5
->active_queries
)
323 uint32_t prims
= u_prims_for_vertices(info
->mode
, info
->count
);
324 vc5
->prims_generated
+= prims
;
327 /* XXX: Only count if we didn't overflow. */
328 vc5
->tf_prims_generated
+= prims
;
333 vc5_update_job_ez(struct vc5_context
*vc5
, struct vc5_job
*job
)
335 switch (vc5
->zsa
->ez_state
) {
336 case VC5_EZ_UNDECIDED
:
337 /* If the Z/S state didn't pick a direction but didn't
338 * disable, then go along with the current EZ state. This
339 * allows EZ optimization for Z func == EQUAL or NEVER.
345 /* If the Z/S state picked a direction, then it needs to match
346 * the current direction if we've decided on one.
348 if (job
->ez_state
== VC5_EZ_UNDECIDED
)
349 job
->ez_state
= vc5
->zsa
->ez_state
;
350 else if (job
->ez_state
!= vc5
->zsa
->ez_state
)
351 job
->ez_state
= VC5_EZ_DISABLED
;
354 case VC5_EZ_DISABLED
:
355 /* If the current Z/S state disables EZ because of a bad Z
356 * func or stencil operation, then we can't do any more EZ in
359 job
->ez_state
= VC5_EZ_DISABLED
;
363 /* If the FS affects the Z of the pixels, then it may update against
364 * the chosen EZ direction (though we could use
365 * ARB_conservative_depth's hints to avoid this)
367 if (vc5
->prog
.fs
->prog_data
.fs
->writes_z
) {
368 job
->ez_state
= VC5_EZ_DISABLED
;
371 if (job
->first_ez_state
== VC5_EZ_UNDECIDED
)
372 job
->first_ez_state
= job
->ez_state
;
376 vc5_draw_vbo(struct pipe_context
*pctx
, const struct pipe_draw_info
*info
)
378 struct vc5_context
*vc5
= vc5_context(pctx
);
380 if (!info
->count_from_stream_output
&& !info
->indirect
&&
381 !info
->primitive_restart
&&
382 !u_trim_pipe_prim(info
->mode
, (unsigned*)&info
->count
))
385 /* Fall back for weird desktop GL primitive restart values. */
386 if (info
->primitive_restart
&&
390 switch (info
->index_size
) {
399 if (info
->restart_index
!= mask
) {
400 util_draw_vbo_without_prim_restart(pctx
, info
);
405 if (info
->mode
>= PIPE_PRIM_QUADS
) {
406 util_primconvert_save_rasterizer_state(vc5
->primconvert
, &vc5
->rasterizer
->base
);
407 util_primconvert_draw_vbo(vc5
->primconvert
, info
);
408 perf_debug("Fallback conversion for %d %s vertices\n",
409 info
->count
, u_prim_name(info
->mode
));
413 /* Before setting up the draw, flush anything writing to the textures
416 vc5_predraw_check_textures(pctx
, &vc5
->verttex
);
417 vc5_predraw_check_textures(pctx
, &vc5
->fragtex
);
419 struct vc5_job
*job
= vc5_get_job_for_fbo(vc5
);
421 /* Get space to emit our draw call into the BCL, using a branch to
422 * jump to a new BO if necessary.
424 vc5_cl_ensure_space_with_branch(&job
->bcl
, 256 /* XXX */);
426 if (vc5
->prim_mode
!= info
->mode
) {
427 vc5
->prim_mode
= info
->mode
;
428 vc5
->dirty
|= VC5_DIRTY_PRIM_MODE
;
432 vc5_update_compiled_shaders(vc5
, info
->mode
);
433 vc5_update_job_ez(vc5
, job
);
435 #if V3D_VERSION >= 41
436 v3d41_emit_state(pctx
);
438 v3d33_emit_state(pctx
);
441 if (vc5
->dirty
& (VC5_DIRTY_VTXBUF
|
443 VC5_DIRTY_PRIM_MODE
|
444 VC5_DIRTY_RASTERIZER
|
445 VC5_DIRTY_COMPILED_CS
|
446 VC5_DIRTY_COMPILED_VS
|
447 VC5_DIRTY_COMPILED_FS
|
448 vc5
->prog
.cs
->uniform_dirty_bits
|
449 vc5
->prog
.vs
->uniform_dirty_bits
|
450 vc5
->prog
.fs
->uniform_dirty_bits
)) {
451 vc5_emit_gl_shader_state(vc5
, info
);
456 /* The Base Vertex/Base Instance packet sets those values to nonzero
457 * for the next draw call only.
459 if (info
->index_bias
|| info
->start_instance
) {
460 cl_emit(&job
->bcl
, BASE_VERTEX_BASE_INSTANCE
, base
) {
461 base
.base_instance
= info
->start_instance
;
462 base
.base_vertex
= info
->index_bias
;
466 uint32_t prim_tf_enable
= 0;
468 /* V3D 3.x: The HW only processes transform feedback on primitives
471 if (vc5
->streamout
.num_targets
)
472 prim_tf_enable
= (V3D_PRIM_POINTS_TF
- V3D_PRIM_POINTS
);
475 vc5_tf_statistics_record(vc5
, info
, vc5
->streamout
.num_targets
);
477 /* Note that the primitive type fields match with OpenGL/gallium
478 * definitions, up to but not including QUADS.
480 if (info
->index_size
) {
481 uint32_t index_size
= info
->index_size
;
482 uint32_t offset
= info
->start
* index_size
;
483 struct pipe_resource
*prsc
;
484 if (info
->has_user_indices
) {
486 u_upload_data(vc5
->uploader
, 0,
487 info
->count
* info
->index_size
, 4,
491 prsc
= info
->index
.resource
;
493 struct vc5_resource
*rsc
= vc5_resource(prsc
);
495 #if V3D_VERSION >= 40
496 cl_emit(&job
->bcl
, INDEX_BUFFER_SETUP
, ib
) {
497 ib
.address
= cl_address(rsc
->bo
, 0);
498 ib
.size
= rsc
->bo
->size
;
502 if (info
->instance_count
> 1) {
503 cl_emit(&job
->bcl
, INDEXED_INSTANCED_PRIMITIVE_LIST
, prim
) {
504 prim
.index_type
= ffs(info
->index_size
) - 1;
505 #if V3D_VERSION >= 40
506 prim
.index_offset
= offset
;
507 #else /* V3D_VERSION < 40 */
508 prim
.maximum_index
= (1u << 31) - 1; /* XXX */
509 prim
.address_of_indices_list
=
510 cl_address(rsc
->bo
, offset
);
511 #endif /* V3D_VERSION < 40 */
512 prim
.mode
= info
->mode
| prim_tf_enable
;
513 prim
.enable_primitive_restarts
= info
->primitive_restart
;
515 prim
.number_of_instances
= info
->instance_count
;
516 prim
.instance_length
= info
->count
;
519 cl_emit(&job
->bcl
, INDEXED_PRIMITIVE_LIST
, prim
) {
520 prim
.index_type
= ffs(info
->index_size
) - 1;
521 prim
.length
= info
->count
;
522 #if V3D_VERSION >= 40
523 prim
.index_offset
= offset
;
524 #else /* V3D_VERSION < 40 */
525 prim
.maximum_index
= (1u << 31) - 1; /* XXX */
526 prim
.address_of_indices_list
=
527 cl_address(rsc
->bo
, offset
);
528 #endif /* V3D_VERSION < 40 */
529 prim
.mode
= info
->mode
| prim_tf_enable
;
530 prim
.enable_primitive_restarts
= info
->primitive_restart
;
534 job
->draw_calls_queued
++;
536 if (info
->has_user_indices
)
537 pipe_resource_reference(&prsc
, NULL
);
539 if (info
->instance_count
> 1) {
540 cl_emit(&job
->bcl
, VERTEX_ARRAY_INSTANCED_PRIMITIVES
, prim
) {
541 prim
.mode
= info
->mode
| prim_tf_enable
;
542 prim
.index_of_first_vertex
= info
->start
;
543 prim
.number_of_instances
= info
->instance_count
;
544 prim
.instance_length
= info
->count
;
547 cl_emit(&job
->bcl
, VERTEX_ARRAY_PRIMITIVES
, prim
) {
548 prim
.mode
= info
->mode
| prim_tf_enable
;
549 prim
.length
= info
->count
;
550 prim
.index_of_first_vertex
= info
->start
;
554 job
->draw_calls_queued
++;
556 if (vc5
->zsa
&& job
->zsbuf
&&
557 (vc5
->zsa
->base
.depth
.enabled
||
558 vc5
->zsa
->base
.stencil
[0].enabled
)) {
559 struct vc5_resource
*rsc
= vc5_resource(job
->zsbuf
->texture
);
560 vc5_job_add_bo(job
, rsc
->bo
);
562 if (vc5
->zsa
->base
.depth
.enabled
) {
563 job
->resolve
|= PIPE_CLEAR_DEPTH
;
564 rsc
->initialized_buffers
= PIPE_CLEAR_DEPTH
;
567 if (vc5
->zsa
->base
.stencil
[0].enabled
) {
568 job
->resolve
|= PIPE_CLEAR_STENCIL
;
569 rsc
->initialized_buffers
|= PIPE_CLEAR_STENCIL
;
573 for (int i
= 0; i
< VC5_MAX_DRAW_BUFFERS
; i
++) {
574 uint32_t bit
= PIPE_CLEAR_COLOR0
<< i
;
576 if (job
->resolve
& bit
|| !job
->cbufs
[i
])
578 struct vc5_resource
*rsc
= vc5_resource(job
->cbufs
[i
]->texture
);
581 vc5_job_add_bo(job
, rsc
->bo
);
584 if (job
->referenced_size
> 768 * 1024 * 1024) {
585 perf_debug("Flushing job with %dkb to try to free up memory\n",
586 job
->referenced_size
/ 1024);
590 if (V3D_DEBUG
& V3D_DEBUG_ALWAYS_FLUSH
)
595 vc5_clear(struct pipe_context
*pctx
, unsigned buffers
,
596 const union pipe_color_union
*color
, double depth
, unsigned stencil
)
598 struct vc5_context
*vc5
= vc5_context(pctx
);
599 struct vc5_job
*job
= vc5_get_job_for_fbo(vc5
);
601 /* We can't flag new buffers for clearing once we've queued draws. We
602 * could avoid this by using the 3d engine to clear.
604 if (job
->draw_calls_queued
) {
605 perf_debug("Flushing rendering to process new clear.\n");
606 vc5_job_submit(vc5
, job
);
607 job
= vc5_get_job_for_fbo(vc5
);
610 for (int i
= 0; i
< VC5_MAX_DRAW_BUFFERS
; i
++) {
611 uint32_t bit
= PIPE_CLEAR_COLOR0
<< i
;
612 if (!(buffers
& bit
))
615 struct pipe_surface
*psurf
= vc5
->framebuffer
.cbufs
[i
];
616 struct vc5_surface
*surf
= vc5_surface(psurf
);
617 struct vc5_resource
*rsc
= vc5_resource(psurf
->texture
);
620 uint32_t internal_size
= 4 << surf
->internal_bpp
;
622 static union pipe_color_union swapped_color
;
623 if (vc5
->swap_color_rb
& (1 << i
)) {
624 swapped_color
.f
[0] = color
->f
[2];
625 swapped_color
.f
[1] = color
->f
[1];
626 swapped_color
.f
[2] = color
->f
[0];
627 swapped_color
.f
[3] = color
->f
[3];
628 color
= &swapped_color
;
631 switch (surf
->internal_type
) {
632 case V3D_INTERNAL_TYPE_8
:
633 util_pack_color(color
->f
, PIPE_FORMAT_R8G8B8A8_UNORM
,
635 memcpy(job
->clear_color
[i
], uc
.ui
, internal_size
);
637 case V3D_INTERNAL_TYPE_8I
:
638 case V3D_INTERNAL_TYPE_8UI
:
639 job
->clear_color
[i
][0] = ((color
->ui
[0] & 0xff) |
640 (color
->ui
[1] & 0xff) << 8 |
641 (color
->ui
[2] & 0xff) << 16 |
642 (color
->ui
[3] & 0xff) << 24);
644 case V3D_INTERNAL_TYPE_16F
:
645 util_pack_color(color
->f
, PIPE_FORMAT_R16G16B16A16_FLOAT
,
647 memcpy(job
->clear_color
[i
], uc
.ui
, internal_size
);
649 case V3D_INTERNAL_TYPE_16I
:
650 case V3D_INTERNAL_TYPE_16UI
:
651 job
->clear_color
[i
][0] = ((color
->ui
[0] & 0xffff) |
653 job
->clear_color
[i
][1] = ((color
->ui
[2] & 0xffff) |
656 case V3D_INTERNAL_TYPE_32F
:
657 case V3D_INTERNAL_TYPE_32I
:
658 case V3D_INTERNAL_TYPE_32UI
:
659 memcpy(job
->clear_color
[i
], color
->ui
, internal_size
);
663 rsc
->initialized_buffers
|= bit
;
666 unsigned zsclear
= buffers
& PIPE_CLEAR_DEPTHSTENCIL
;
668 struct vc5_resource
*rsc
=
669 vc5_resource(vc5
->framebuffer
.zsbuf
->texture
);
671 if (zsclear
& PIPE_CLEAR_DEPTH
)
672 job
->clear_z
= depth
;
673 if (zsclear
& PIPE_CLEAR_STENCIL
)
674 job
->clear_s
= stencil
;
676 rsc
->initialized_buffers
|= zsclear
;
681 job
->draw_max_x
= vc5
->framebuffer
.width
;
682 job
->draw_max_y
= vc5
->framebuffer
.height
;
683 job
->cleared
|= buffers
;
684 job
->resolve
|= buffers
;
690 vc5_clear_render_target(struct pipe_context
*pctx
, struct pipe_surface
*ps
,
691 const union pipe_color_union
*color
,
692 unsigned x
, unsigned y
, unsigned w
, unsigned h
,
693 bool render_condition_enabled
)
695 fprintf(stderr
, "unimpl: clear RT\n");
699 vc5_clear_depth_stencil(struct pipe_context
*pctx
, struct pipe_surface
*ps
,
700 unsigned buffers
, double depth
, unsigned stencil
,
701 unsigned x
, unsigned y
, unsigned w
, unsigned h
,
702 bool render_condition_enabled
)
704 fprintf(stderr
, "unimpl: clear DS\n");
708 v3dX(draw_init
)(struct pipe_context
*pctx
)
710 pctx
->draw_vbo
= vc5_draw_vbo
;
711 pctx
->clear
= vc5_clear
;
712 pctx
->clear_render_target
= vc5_clear_render_target
;
713 pctx
->clear_depth_stencil
= vc5_clear_depth_stencil
;