llvmpipe: implement GL_ARB_sample_locations

Needing the positions both in the scene for rasterization (in fixed point)
and in the fs (as floats) is a bit awkward, for now just put it in fs key.
Otherwise pretty straight forward.

Reviewed-by: Michal Krol <michal.krol@broadcom.com>
Reviewed-by: Brian Paul <brian.paul@broadcom.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/37181>
This commit is contained in:
Roland Scheidegger
2025-09-04 13:13:16 +02:00
committed by Marge Bot
parent 60924b4819
commit b0be900f93
12 changed files with 173 additions and 41 deletions
+1 -1
View File
@@ -305,7 +305,7 @@ Khronos, ARB, and OES extensions that are not part of any OpenGL or OpenGL ES ve
GL_ARB_parallel_shader_compile DONE (freedreno, llvmpipe, radeonsi, etnaviv, virgl, zink, iris, crocus/gen6+, asahi)
GL_ARB_post_depth_coverage DONE (freedreno/a6xx, nvc0, radeonsi, llvmpipe, zink, iris/gen9+)
GL_ARB_robustness_isolation not started
GL_ARB_sample_locations DONE (freedreno/a6xx, nvc0, zink)
GL_ARB_sample_locations DONE (freedreno/a6xx, nvc0, zink, llvmpipe)
GL_ARB_seamless_cubemap_per_texture DONE (etnaviv/SEAMLESS_CUBE_MAP, freedreno, nvc0, r600, radeonsi, softpipe, llvmpipe, virgl, zink, asahi, iris, crocus)
GL_ARB_shader_ballot DONE (llvmpipe, nvc0, radeonsi, zink, iris, crocus/gen8, d3d12, asahi)
GL_ARB_shader_clock DONE (freedreno/a6xx, nv50, nvc0, r600, radeonsi, llvmpipe, virgl, panfrost/v6+, zink, iris, crocus/gen7+)
@@ -83,6 +83,8 @@ struct llvmpipe_context {
/** Other rendering state */
unsigned sample_mask;
unsigned min_samples;
uint8_t sample_locations[LP_MAX_SAMPLES];
bool sample_locations_enabled;
struct pipe_blend_color blend_color;
struct pipe_stencil_ref stencil_ref;
struct pipe_clip_state clip;
-12
View File
@@ -639,18 +639,6 @@ lp_scene_begin_binning(struct lp_scene *scene,
}
scene->fb_max_layer = max_layer;
scene->fb_max_samples = util_framebuffer_get_num_samples(fb);
if (scene->fb_max_samples == 4) {
for (unsigned i = 0; i < 4; i++) {
scene->fixed_sample_pos[i][0] = util_iround(lp_sample_pos_4x[i][0] * FIXED_ONE);
scene->fixed_sample_pos[i][1] = util_iround(lp_sample_pos_4x[i][1] * FIXED_ONE);
}
} else if (scene->fb_max_samples == 8) {
for (unsigned i = 0; i < 8; i++) {
scene->fixed_sample_pos[i][0] = util_iround(lp_sample_pos_8x[i][0] * FIXED_ONE);
scene->fixed_sample_pos[i][1] = util_iround(lp_sample_pos_8x[i][1] * FIXED_ONE);
}
}
}
+22
View File
@@ -360,6 +360,7 @@ llvmpipe_init_screen_caps(struct pipe_screen *screen)
caps->memobj = true;
#endif
caps->sampler_reduction_minmax = true;
caps->programmable_sample_locations = true;
caps->texture_query_samples = true;
caps->shader_group_vote = true;
caps->shader_ballot = true;
@@ -391,6 +392,26 @@ llvmpipe_init_screen_caps(struct pipe_screen *screen)
}
static void
llvmpipe_get_sample_pixel_grid(struct pipe_screen *pscreen,
unsigned sample_count,
unsigned *width, unsigned *height)
{
switch (sample_count) {
case 0:
case 1:
case 2:
case 4:
case 8:
*width = 1;
*height = 1;
break;
default:
UNREACHABLE("illegal sample count");
}
}
static void
llvmpipe_get_driver_uuid(struct pipe_screen *pscreen, char *uuid)
{
@@ -967,6 +988,7 @@ llvmpipe_create_screen(struct sw_winsys *winsys)
screen->base.get_device_vendor = llvmpipe_get_vendor; // TODO should be the CPU vendor
screen->base.get_screen_fd = llvmpipe_screen_get_fd;
screen->base.is_format_supported = llvmpipe_is_format_supported;
screen->base.get_sample_pixel_grid = llvmpipe_get_sample_pixel_grid;
screen->base.context_create = llvmpipe_create_context;
screen->base.flush_frontbuffer = llvmpipe_flush_frontbuffer;
+45 -1
View File
@@ -113,6 +113,35 @@ lp_setup_get_empty_scene(struct lp_setup_context *setup)
setup->scene = setup->scenes[i];
setup->scene->permit_linear_rasterizer = setup->permit_linear_rasterizer;
/* XXX: doing that here is ugly... */
setup->scene->fb_max_samples = util_framebuffer_get_num_samples(&setup->fb);
if (setup->scene->fb_max_samples == 4) {
if (setup->sample_locations_enabled) {
for (unsigned i = 0; i < 4; i++) {
setup->scene->fixed_sample_pos[i][0] = (setup->sample_locations[i] & 0xF) << (FIXED_ORDER - 4);
setup->scene->fixed_sample_pos[i][1] = (setup->sample_locations[i] >> 4) << (FIXED_ORDER - 4);
}
} else {
for (unsigned i = 0; i < 4; i++) {
setup->scene->fixed_sample_pos[i][0] = util_iround(lp_sample_pos_4x[i][0] * FIXED_ONE);
setup->scene->fixed_sample_pos[i][1] = util_iround(lp_sample_pos_4x[i][1] * FIXED_ONE);
}
}
} else if (setup->scene->fb_max_samples == 8) {
if (setup->sample_locations_enabled) {
for (unsigned i = 0; i < 8; i++) {
setup->scene->fixed_sample_pos[i][0] = (setup->sample_locations[i] & 0xF) << (FIXED_ORDER - 4);
setup->scene->fixed_sample_pos[i][1] = (setup->sample_locations[i] >> 4) << (FIXED_ORDER - 4);
}
} else {
for (unsigned i = 0; i < 8; i++) {
setup->scene->fixed_sample_pos[i][0] = util_iround(lp_sample_pos_8x[i][0] * FIXED_ONE);
setup->scene->fixed_sample_pos[i][1] = util_iround(lp_sample_pos_8x[i][1] * FIXED_ONE);
}
}
}
lp_scene_begin_binning(setup->scene, &setup->fb);
}
@@ -165,7 +194,7 @@ first_point(struct lp_setup_context *setup,
}
void
static void
lp_setup_reset(struct lp_setup_context *setup)
{
LP_DBG(DEBUG_SETUP, "%s\n", __func__);
@@ -415,6 +444,21 @@ lp_setup_bind_framebuffer(struct lp_setup_context *setup,
}
void
lp_setup_set_sample_locations(struct lp_setup_context *setup,
bool sample_locations_enabled,
const uint8_t *sample_locations)
{
LP_DBG(DEBUG_SETUP, "%s\n", __func__);
set_scene_state(setup, SETUP_FLUSHED, __func__);
assert(!setup->scene);
setup->sample_locations_enabled = sample_locations_enabled;
memcpy(setup->sample_locations, sample_locations, sizeof(setup->sample_locations));
}
/*
* Try to clear one color buffer of the attached fb, either by binning a clear
* command or queuing up the clear for later (when binning is started).
+5 -3
View File
@@ -45,9 +45,6 @@ struct pipe_fence_handle;
struct lp_setup_variant;
struct lp_setup_context;
void
lp_setup_reset(struct lp_setup_context *setup);
struct lp_setup_context *
lp_setup_create(struct pipe_context *pipe,
struct draw_context *draw);
@@ -134,6 +131,11 @@ void
lp_setup_set_sample_mask(struct lp_setup_context *setup,
uint32_t sample_mask);
void
lp_setup_set_sample_locations(struct lp_setup_context *setup,
bool sample_locations_enabled,
const uint8_t *sample_locations);
void
lp_setup_set_rasterizer_discard(struct lp_setup_context *setup,
bool rasterizer_discard);
@@ -110,7 +110,8 @@ struct lp_setup_context
unsigned multisample:1;
unsigned rectangular_lines:1;
unsigned cullmode:2; /**< PIPE_FACE_x */
unsigned bottom_edge_rule;
unsigned bottom_edge_rule:1;
unsigned sample_locations_enabled:1;
float pixel_offset;
float line_width;
float point_size;
@@ -118,6 +119,7 @@ struct lp_setup_context
int8_t viewport_index_slot;
int8_t layer_slot;
int8_t face_slot;
uint8_t sample_locations[LP_MAX_SAMPLES];
struct pipe_framebuffer_state fb;
struct u_rect framebuffer;
+13 -12
View File
@@ -61,18 +61,19 @@
#define LP_NEW_TCS 0x200000
#define LP_NEW_TES 0x400000
#define LP_NEW_SAMPLE_MASK 0x800000
#define LP_NEW_TASK 0x1000000
#define LP_NEW_TASK_CONSTANTS 0x2000000
#define LP_NEW_TASK_SAMPLER 0x4000000
#define LP_NEW_TASK_SAMPLER_VIEW 0x8000000
#define LP_NEW_TASK_SSBOS 0x10000000
#define LP_NEW_TASK_IMAGES 0x20000000
#define LP_NEW_MESH 0x40000000
#define LP_NEW_MESH_CONSTANTS 0x80000000
#define LP_NEW_MESH_SAMPLER 0x100000000ULL
#define LP_NEW_MESH_SAMPLER_VIEW 0x200000000ULL
#define LP_NEW_MESH_SSBOS 0x400000000ULL
#define LP_NEW_MESH_IMAGES 0x800000000ULL
#define LP_NEW_SAMPLE_LOCATIONS 0x1000000
#define LP_NEW_TASK 0x2000000
#define LP_NEW_TASK_CONSTANTS 0x4000000
#define LP_NEW_TASK_SAMPLER 0x8000000
#define LP_NEW_TASK_SAMPLER_VIEW 0x10000000
#define LP_NEW_TASK_SSBOS 0x20000000
#define LP_NEW_TASK_IMAGES 0x40000000
#define LP_NEW_MESH 0x80000000
#define LP_NEW_MESH_CONSTANTS 0x100000000ULL
#define LP_NEW_MESH_SAMPLER 0x200000000ULL
#define LP_NEW_MESH_SAMPLER_VIEW 0x400000000ULL
#define LP_NEW_MESH_SSBOS 0x800000000ULL
#define LP_NEW_MESH_IMAGES 0x1000000000ULL
#define LP_CSNEW_CS 0x1
#define LP_CSNEW_CONSTANTS 0x2
@@ -197,6 +197,29 @@ llvmpipe_set_min_samples(struct pipe_context *pipe,
}
}
static void
llvmpipe_set_sample_locations(struct pipe_context *pipe,
size_t size, const uint8_t *locations)
{
struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
bool sample_locations_enabled = size && locations;
assert(size <= sizeof(llvmpipe->sample_locations));
if (sample_locations_enabled != llvmpipe->sample_locations_enabled) {
llvmpipe->sample_locations_enabled = sample_locations_enabled;
llvmpipe->dirty |= LP_NEW_SAMPLE_LOCATIONS;
}
if (sample_locations_enabled &&
memcmp(locations, llvmpipe->sample_locations, size)) {
memcpy(llvmpipe->sample_locations, locations, size);
llvmpipe->dirty |= LP_NEW_SAMPLE_LOCATIONS;
}
}
void
llvmpipe_init_blend_funcs(struct llvmpipe_context *llvmpipe)
{
@@ -213,6 +236,7 @@ llvmpipe_init_blend_funcs(struct llvmpipe_context *llvmpipe)
llvmpipe->pipe.set_stencil_ref = llvmpipe_set_stencil_ref;
llvmpipe->pipe.set_sample_mask = llvmpipe_set_sample_mask;
llvmpipe->pipe.set_min_samples = llvmpipe_set_min_samples;
llvmpipe->pipe.set_sample_locations = llvmpipe_set_sample_locations;
llvmpipe->dirty |= LP_NEW_SAMPLE_MASK;
llvmpipe->sample_mask = ~0;
@@ -306,7 +306,8 @@ llvmpipe_update_derived(struct llvmpipe_context *llvmpipe)
LP_NEW_RASTERIZER |
LP_NEW_SAMPLER |
LP_NEW_SAMPLER_VIEW |
LP_NEW_OCCLUSION_QUERY))
LP_NEW_OCCLUSION_QUERY |
LP_NEW_SAMPLE_LOCATIONS))
llvmpipe_update_fs(llvmpipe);
if (llvmpipe->dirty & (LP_NEW_FS |
@@ -331,6 +332,11 @@ llvmpipe_update_derived(struct llvmpipe_context *llvmpipe)
lp_setup_set_blend_color(llvmpipe->setup,
&llvmpipe->blend_color);
if (llvmpipe->dirty & LP_NEW_SAMPLE_LOCATIONS)
lp_setup_set_sample_locations(llvmpipe->setup,
llvmpipe->sample_locations_enabled,
llvmpipe->sample_locations);
if (llvmpipe->dirty & LP_NEW_SCISSOR)
lp_setup_set_scissors(llvmpipe->setup, llvmpipe->scissors);
+49 -10
View File
@@ -3362,22 +3362,44 @@ generate_fragment(struct llvmpipe_context *lp,
if (key->multisample && key->coverage_samples == 4) {
LLVMValueRef sample_pos_arr[8];
for (unsigned i = 0; i < 4; i++) {
sample_pos_arr[i * 2] = LLVMConstReal(flt_type,
lp_sample_pos_4x[i][0]);
sample_pos_arr[i * 2 + 1] = LLVMConstReal(flt_type,
lp_sample_pos_4x[i][1]);
if (key->sample_locations_enabled) {
for (unsigned i = 0; i < 4; i++) {
/*
* sample_locations holds 4 bit values, just divide by 16
* to get subpixel offset as float
*/
sample_pos_arr[i * 2] = LLVMConstReal(flt_type,
(key->sample_locations[i] & 0xF) * 0.0625);
sample_pos_arr[i * 2 + 1] = LLVMConstReal(flt_type,
(key->sample_locations[i] >> 4) * 0.0625);
}
} else {
for (unsigned i = 0; i < 4; i++) {
sample_pos_arr[i * 2] = LLVMConstReal(flt_type,
lp_sample_pos_4x[i][0]);
sample_pos_arr[i * 2 + 1] = LLVMConstReal(flt_type,
lp_sample_pos_4x[i][1]);
}
}
sample_pos_array =
LLVMConstArray(LLVMFloatTypeInContext(gallivm->context),
sample_pos_arr, 8);
} else if (key->multisample && key->coverage_samples == 8) {
LLVMValueRef sample_pos_arr[16];
for (unsigned i = 0; i < 8; i++) {
sample_pos_arr[i * 2] = LLVMConstReal(flt_type,
lp_sample_pos_8x[i][0]);
sample_pos_arr[i * 2 + 1] = LLVMConstReal(flt_type,
lp_sample_pos_8x[i][1]);
if (key->sample_locations_enabled) {
for (unsigned i = 0; i < 8; i++) {
sample_pos_arr[i * 2] = LLVMConstReal(flt_type,
(key->sample_locations[i] & 0xF) * 0.0625);
sample_pos_arr[i * 2 + 1] = LLVMConstReal(flt_type,
(key->sample_locations[i] >> 4) * 0.0625);
}
} else {
for (unsigned i = 0; i < 8; i++) {
sample_pos_arr[i * 2] = LLVMConstReal(flt_type,
lp_sample_pos_8x[i][0]);
sample_pos_arr[i * 2 + 1] = LLVMConstReal(flt_type,
lp_sample_pos_8x[i][1]);
}
}
sample_pos_array =
LLVMConstArray(LLVMFloatTypeInContext(gallivm->context),
@@ -3616,6 +3638,15 @@ dump_fs_variant_key(struct lp_fragment_shader_variant_key *key)
debug_printf("coverage samples = %d\n", key->coverage_samples);
debug_printf("min samples = %d\n", key->min_samples);
}
if (key->sample_locations_enabled) {
debug_printf("sample_locations_enabled = 1\n");
for (unsigned i = 0; i < LP_MAX_SAMPLES; i++) {
debug_printf("sample %d loc x = %d y = %d\n", i,
key->sample_locations[i] & 0xF, key->sample_locations[i] >> 4);
}
}
for (unsigned i = 0; i < key->nr_cbufs; ++i) {
debug_printf("cbuf_format[%u] = %s\n", i, util_format_name(key->cbuf_format[i]));
debug_printf("cbuf nr_samples[%u] = %d\n", i, key->cbuf_nr_samples[i]);
@@ -4538,6 +4569,14 @@ make_variant_key(struct llvmpipe_context *lp,
if (lp->min_samples > 1 || nir->info.fs.uses_fbfetch_output)
key->min_samples = key->coverage_samples;
}
if (key->multisample) {
key->sample_locations_enabled = lp->sample_locations_enabled;
if (key->sample_locations_enabled) {
memcpy(key->sample_locations, lp->sample_locations, sizeof(key->sample_locations));
}
}
key->nr_cbufs = lp->framebuffer.nr_cbufs;
if (!key->blend.independent_blend_enable) {
@@ -87,6 +87,7 @@ struct lp_fragment_shader_variant_key
unsigned multisample:1;
unsigned no_ms_sample_mask_out:1;
unsigned restrict_depth_values:1;
unsigned sample_locations_enabled:1;
enum pipe_format zsbuf_format;
enum pipe_format cbuf_format[PIPE_MAX_COLOR_BUFS];
@@ -95,6 +96,7 @@ struct lp_fragment_shader_variant_key
uint8_t zsbuf_nr_samples;
uint8_t coverage_samples;
uint8_t min_samples;
uint8_t sample_locations[LP_MAX_SAMPLES]; /* maybe pass this through scene? */
/* followed by variable number of samplers + images */
};