diff --git a/docs/features.txt b/docs/features.txt index c7e8fb2586c..8c78cce677e 100644 --- a/docs/features.txt +++ b/docs/features.txt @@ -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+) diff --git a/src/gallium/drivers/llvmpipe/lp_context.h b/src/gallium/drivers/llvmpipe/lp_context.h index defb4037744..9716d1e88b6 100644 --- a/src/gallium/drivers/llvmpipe/lp_context.h +++ b/src/gallium/drivers/llvmpipe/lp_context.h @@ -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; diff --git a/src/gallium/drivers/llvmpipe/lp_scene.c b/src/gallium/drivers/llvmpipe/lp_scene.c index f8fed129a73..b2f25b77078 100644 --- a/src/gallium/drivers/llvmpipe/lp_scene.c +++ b/src/gallium/drivers/llvmpipe/lp_scene.c @@ -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); - } - } } diff --git a/src/gallium/drivers/llvmpipe/lp_screen.c b/src/gallium/drivers/llvmpipe/lp_screen.c index 7ea7a90969c..2aec374fcd4 100644 --- a/src/gallium/drivers/llvmpipe/lp_screen.c +++ b/src/gallium/drivers/llvmpipe/lp_screen.c @@ -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; diff --git a/src/gallium/drivers/llvmpipe/lp_setup.c b/src/gallium/drivers/llvmpipe/lp_setup.c index 88c0d9d8d37..67c12d5185b 100644 --- a/src/gallium/drivers/llvmpipe/lp_setup.c +++ b/src/gallium/drivers/llvmpipe/lp_setup.c @@ -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). diff --git a/src/gallium/drivers/llvmpipe/lp_setup.h b/src/gallium/drivers/llvmpipe/lp_setup.h index 28ae673f6f7..648d50a53ab 100644 --- a/src/gallium/drivers/llvmpipe/lp_setup.h +++ b/src/gallium/drivers/llvmpipe/lp_setup.h @@ -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); diff --git a/src/gallium/drivers/llvmpipe/lp_setup_context.h b/src/gallium/drivers/llvmpipe/lp_setup_context.h index 469a0c69167..af7aa50c233 100644 --- a/src/gallium/drivers/llvmpipe/lp_setup_context.h +++ b/src/gallium/drivers/llvmpipe/lp_setup_context.h @@ -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; diff --git a/src/gallium/drivers/llvmpipe/lp_state.h b/src/gallium/drivers/llvmpipe/lp_state.h index acd486cb331..f9803fa80a3 100644 --- a/src/gallium/drivers/llvmpipe/lp_state.h +++ b/src/gallium/drivers/llvmpipe/lp_state.h @@ -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 diff --git a/src/gallium/drivers/llvmpipe/lp_state_blend.c b/src/gallium/drivers/llvmpipe/lp_state_blend.c index 6b660c2ec7f..8a4f530a5f6 100644 --- a/src/gallium/drivers/llvmpipe/lp_state_blend.c +++ b/src/gallium/drivers/llvmpipe/lp_state_blend.c @@ -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; diff --git a/src/gallium/drivers/llvmpipe/lp_state_derived.c b/src/gallium/drivers/llvmpipe/lp_state_derived.c index 1de2d22198d..a1f5133ffe0 100644 --- a/src/gallium/drivers/llvmpipe/lp_state_derived.c +++ b/src/gallium/drivers/llvmpipe/lp_state_derived.c @@ -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); diff --git a/src/gallium/drivers/llvmpipe/lp_state_fs.c b/src/gallium/drivers/llvmpipe/lp_state_fs.c index df79657b16d..5e1384210b8 100644 --- a/src/gallium/drivers/llvmpipe/lp_state_fs.c +++ b/src/gallium/drivers/llvmpipe/lp_state_fs.c @@ -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) { diff --git a/src/gallium/drivers/llvmpipe/lp_state_fs.h b/src/gallium/drivers/llvmpipe/lp_state_fs.h index 2764d6c750f..74998dfffca 100644 --- a/src/gallium/drivers/llvmpipe/lp_state_fs.h +++ b/src/gallium/drivers/llvmpipe/lp_state_fs.h @@ -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 */ };