This hooks up compute shader creation and launch grid support. Reviewed-by: Gurchetan Singh <gurchetansingh@chromium.org>tags/18.2-branchpoint
@@ -506,7 +506,7 @@ static void *virgl_shader_encoder(struct pipe_context *ctx, | |||
handle = virgl_object_assign_handle(); | |||
/* encode VS state */ | |||
ret = virgl_encode_shader_state(vctx, handle, type, | |||
&shader->stream_output, | |||
&shader->stream_output, 0, | |||
new_tokens); | |||
if (ret) { | |||
return NULL; | |||
@@ -961,7 +961,7 @@ static void virgl_set_shader_buffers(struct pipe_context *ctx, | |||
pipe_resource_reference(&vctx->ssbos[shader][idx], NULL); | |||
} | |||
uint32_t max_shader_buffer = shader == PIPE_SHADER_FRAGMENT ? | |||
uint32_t max_shader_buffer = (shader == PIPE_SHADER_FRAGMENT || shader == PIPE_SHADER_COMPUTE) ? | |||
rs->caps.caps.v2.max_shader_buffer_frag_compute : | |||
rs->caps.caps.v2.max_shader_buffer_other_stages; | |||
if (!max_shader_buffer) | |||
@@ -989,7 +989,7 @@ static void virgl_set_shader_images(struct pipe_context *ctx, | |||
pipe_resource_reference(&vctx->images[shader][idx], NULL); | |||
} | |||
uint32_t max_shader_images = shader == PIPE_SHADER_FRAGMENT ? | |||
uint32_t max_shader_images = (shader == PIPE_SHADER_FRAGMENT || shader == PIPE_SHADER_COMPUTE) ? | |||
rs->caps.caps.v2.max_shader_image_frag_compute : | |||
rs->caps.caps.v2.max_shader_image_other_stages; | |||
if (!max_shader_images) | |||
@@ -1008,6 +1008,50 @@ static void virgl_memory_barrier(struct pipe_context *ctx, | |||
virgl_encode_memory_barrier(vctx, flags); | |||
} | |||
static void *virgl_create_compute_state(struct pipe_context *ctx, | |||
const struct pipe_compute_state *state) | |||
{ | |||
struct virgl_context *vctx = virgl_context(ctx); | |||
uint32_t handle; | |||
const struct tgsi_token *new_tokens = state->prog; | |||
struct pipe_stream_output_info so_info = {}; | |||
int ret; | |||
handle = virgl_object_assign_handle(); | |||
ret = virgl_encode_shader_state(vctx, handle, PIPE_SHADER_COMPUTE, | |||
&so_info, | |||
state->req_local_mem, | |||
new_tokens); | |||
if (ret) { | |||
return NULL; | |||
} | |||
return (void *)(unsigned long)handle; | |||
} | |||
static void virgl_bind_compute_state(struct pipe_context *ctx, void *state) | |||
{ | |||
uint32_t handle = (unsigned long)state; | |||
struct virgl_context *vctx = virgl_context(ctx); | |||
virgl_encode_bind_shader(vctx, handle, PIPE_SHADER_COMPUTE); | |||
} | |||
static void virgl_delete_compute_state(struct pipe_context *ctx, void *state) | |||
{ | |||
uint32_t handle = (unsigned long)state; | |||
struct virgl_context *vctx = virgl_context(ctx); | |||
virgl_encode_delete_object(vctx, handle, VIRGL_OBJECT_SHADER); | |||
} | |||
static void virgl_launch_grid(struct pipe_context *ctx, | |||
const struct pipe_grid_info *info) | |||
{ | |||
struct virgl_context *vctx = virgl_context(ctx); | |||
virgl_encode_launch_grid(vctx, info); | |||
} | |||
static void | |||
virgl_context_destroy( struct pipe_context *ctx ) | |||
{ | |||
@@ -1118,6 +1162,11 @@ struct pipe_context *virgl_context_create(struct pipe_screen *pscreen, | |||
vctx->base.delete_gs_state = virgl_delete_gs_state; | |||
vctx->base.delete_fs_state = virgl_delete_fs_state; | |||
vctx->base.create_compute_state = virgl_create_compute_state; | |||
vctx->base.bind_compute_state = virgl_bind_compute_state; | |||
vctx->base.delete_compute_state = virgl_delete_compute_state; | |||
vctx->base.launch_grid = virgl_launch_grid; | |||
vctx->base.clear = virgl_clear; | |||
vctx->base.draw_vbo = virgl_draw_vbo; | |||
vctx->base.flush = virgl_flush_from_st; |
@@ -241,6 +241,7 @@ int virgl_encode_shader_state(struct virgl_context *ctx, | |||
uint32_t handle, | |||
uint32_t type, | |||
const struct pipe_stream_output_info *so_info, | |||
uint32_t cs_req_local_mem, | |||
const struct tgsi_token *tokens) | |||
{ | |||
char *str, *sptr; | |||
@@ -298,7 +299,10 @@ int virgl_encode_shader_state(struct virgl_context *ctx, | |||
virgl_emit_shader_header(ctx, handle, len, type, offlen, num_tokens); | |||
virgl_emit_shader_streamout(ctx, first_pass ? so_info : NULL); | |||
if (type == PIPE_SHADER_COMPUTE) | |||
virgl_encoder_write_dword(ctx->cbuf, cs_req_local_mem); | |||
else | |||
virgl_emit_shader_streamout(ctx, first_pass ? so_info : NULL); | |||
virgl_encoder_write_block(ctx->cbuf, (uint8_t *)sptr, length); | |||
@@ -980,3 +984,22 @@ int virgl_encode_memory_barrier(struct virgl_context *ctx, | |||
virgl_encoder_write_dword(ctx->cbuf, flags); | |||
return 0; | |||
} | |||
int virgl_encode_launch_grid(struct virgl_context *ctx, | |||
const struct pipe_grid_info *grid_info) | |||
{ | |||
virgl_encoder_write_cmd_dword(ctx, VIRGL_CMD0(VIRGL_CCMD_LAUNCH_GRID, 0, VIRGL_LAUNCH_GRID_SIZE)); | |||
virgl_encoder_write_dword(ctx->cbuf, grid_info->block[0]); | |||
virgl_encoder_write_dword(ctx->cbuf, grid_info->block[1]); | |||
virgl_encoder_write_dword(ctx->cbuf, grid_info->block[2]); | |||
virgl_encoder_write_dword(ctx->cbuf, grid_info->grid[0]); | |||
virgl_encoder_write_dword(ctx->cbuf, grid_info->grid[1]); | |||
virgl_encoder_write_dword(ctx->cbuf, grid_info->grid[2]); | |||
if (grid_info->indirect) { | |||
struct virgl_resource *res = virgl_resource(grid_info->indirect); | |||
virgl_encoder_write_res(ctx, res); | |||
} else | |||
virgl_encoder_write_dword(ctx->cbuf, 0); | |||
virgl_encoder_write_dword(ctx->cbuf, grid_info->indirect_offset); | |||
return 0; | |||
} |
@@ -90,6 +90,7 @@ extern int virgl_encode_shader_state(struct virgl_context *ctx, | |||
uint32_t handle, | |||
uint32_t type, | |||
const struct pipe_stream_output_info *so_info, | |||
uint32_t cs_req_local_mem, | |||
const struct tgsi_token *tokens); | |||
int virgl_encode_stream_output_info(struct virgl_context *ctx, | |||
@@ -269,4 +270,6 @@ int virgl_encode_set_shader_images(struct virgl_context *ctx, | |||
const struct pipe_image_view *images); | |||
int virgl_encode_memory_barrier(struct virgl_context *ctx, | |||
unsigned flags); | |||
int virgl_encode_launch_grid(struct virgl_context *ctx, | |||
const struct pipe_grid_info *grid_info); | |||
#endif |
@@ -206,6 +206,7 @@ enum virgl_formats { | |||
#define VIRGL_CAP_TGSI_PRECISE (1 << 4) | |||
#define VIRGL_CAP_TXQS (1 << 5) | |||
#define VIRGL_CAP_MEMORY_BARRIER (1 << 6) | |||
#define VIRGL_CAP_COMPUTE_SHADER (1 << 7) | |||
#define VIRGL_BIND_DEPTH_STENCIL (1 << 0) | |||
#define VIRGL_BIND_RENDER_TARGET (1 << 1) | |||
@@ -312,6 +313,10 @@ struct virgl_caps_v2 { | |||
uint32_t max_shader_image_frag_compute; | |||
uint32_t max_shader_image_other_stages; | |||
uint32_t max_image_samples; | |||
uint32_t max_compute_work_group_invocations; | |||
uint32_t max_compute_shared_memory_size; | |||
uint32_t max_compute_grid_size[3]; | |||
uint32_t max_compute_block_size[3]; | |||
}; | |||
union virgl_caps { |
@@ -89,6 +89,7 @@ enum virgl_context_cmd { | |||
VIRGL_CCMD_SET_SHADER_BUFFERS, | |||
VIRGL_CCMD_SET_SHADER_IMAGES, | |||
VIRGL_CCMD_MEMORY_BARRIER, | |||
VIRGL_CCMD_LAUNCH_GRID, | |||
}; | |||
/* | |||
@@ -518,4 +519,14 @@ enum virgl_context_cmd { | |||
#define VIRGL_MEMORY_BARRIER_SIZE 1 | |||
#define VIRGL_MEMORY_BARRIER_FLAGS 1 | |||
#define VIRGL_LAUNCH_GRID_SIZE 8 | |||
#define VIRGL_LAUNCH_BLOCK_X 1 | |||
#define VIRGL_LAUNCH_BLOCK_Y 2 | |||
#define VIRGL_LAUNCH_BLOCK_Z 3 | |||
#define VIRGL_LAUNCH_GRID_X 4 | |||
#define VIRGL_LAUNCH_GRID_Y 5 | |||
#define VIRGL_LAUNCH_GRID_Z 6 | |||
#define VIRGL_LAUNCH_INDIRECT_HANDLE 7 | |||
#define VIRGL_LAUNCH_INDIRECT_OFFSET 8 | |||
#endif |
@@ -139,7 +139,7 @@ virgl_get_param(struct pipe_screen *screen, enum pipe_cap param) | |||
case PIPE_CAP_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION: | |||
return 0; | |||
case PIPE_CAP_COMPUTE: | |||
return 0; | |||
return vscreen->caps.caps.v2.capability_bits & VIRGL_CAP_COMPUTE_SHADER; | |||
case PIPE_CAP_USER_VERTEX_BUFFERS: | |||
return 0; | |||
case PIPE_CAP_CONSTANT_BUFFER_OFFSET_ALIGNMENT: | |||
@@ -328,6 +328,10 @@ virgl_get_shader_param(struct pipe_screen *screen, | |||
!vscreen->caps.caps.v1.bset.has_tessellation_shaders) | |||
return 0; | |||
if (shader == PIPE_SHADER_COMPUTE && | |||
!(vscreen->caps.caps.v2.capability_bits & VIRGL_CAP_COMPUTE_SHADER)) | |||
return 0; | |||
switch(shader) | |||
{ | |||
case PIPE_SHADER_FRAGMENT: | |||
@@ -335,6 +339,7 @@ virgl_get_shader_param(struct pipe_screen *screen, | |||
case PIPE_SHADER_GEOMETRY: | |||
case PIPE_SHADER_TESS_CTRL: | |||
case PIPE_SHADER_TESS_EVAL: | |||
case PIPE_SHADER_COMPUTE: | |||
switch (param) { | |||
case PIPE_SHADER_CAP_MAX_INSTRUCTIONS: | |||
case PIPE_SHADER_CAP_MAX_ALU_INSTRUCTIONS: | |||
@@ -373,15 +378,17 @@ virgl_get_shader_param(struct pipe_screen *screen, | |||
case PIPE_SHADER_CAP_MAX_CONST_BUFFER_SIZE: | |||
return 4096 * sizeof(float[4]); | |||
case PIPE_SHADER_CAP_MAX_SHADER_BUFFERS: | |||
if (shader == PIPE_SHADER_FRAGMENT) | |||
if (shader == PIPE_SHADER_FRAGMENT || shader == PIPE_SHADER_COMPUTE) | |||
return vscreen->caps.caps.v2.max_shader_buffer_frag_compute; | |||
else | |||
return vscreen->caps.caps.v2.max_shader_buffer_other_stages; | |||
case PIPE_SHADER_CAP_MAX_SHADER_IMAGES: | |||
if (shader == PIPE_SHADER_FRAGMENT) | |||
if (shader == PIPE_SHADER_FRAGMENT || shader == PIPE_SHADER_COMPUTE) | |||
return vscreen->caps.caps.v2.max_shader_image_frag_compute; | |||
else | |||
return vscreen->caps.caps.v2.max_shader_image_other_stages; | |||
case PIPE_SHADER_CAP_SUPPORTED_IRS: | |||
return (1 << PIPE_SHADER_IR_TGSI); | |||
case PIPE_SHADER_CAP_LOWER_IF_THRESHOLD: | |||
case PIPE_SHADER_CAP_TGSI_SKIP_MERGE_REGISTERS: | |||
case PIPE_SHADER_CAP_INT64_ATOMICS: | |||
@@ -426,6 +433,51 @@ virgl_get_paramf(struct pipe_screen *screen, enum pipe_capf param) | |||
return 0.0; | |||
} | |||
static int | |||
virgl_get_compute_param(struct pipe_screen *screen, | |||
enum pipe_shader_ir ir_type, | |||
enum pipe_compute_cap param, | |||
void *ret) | |||
{ | |||
struct virgl_screen *vscreen = virgl_screen(screen); | |||
if (!(vscreen->caps.caps.v2.capability_bits & VIRGL_CAP_COMPUTE_SHADER)) | |||
return 0; | |||
switch (param) { | |||
case PIPE_COMPUTE_CAP_MAX_GRID_SIZE: | |||
if (ret) { | |||
uint64_t *grid_size = ret; | |||
grid_size[0] = vscreen->caps.caps.v2.max_compute_grid_size[0]; | |||
grid_size[1] = vscreen->caps.caps.v2.max_compute_grid_size[1]; | |||
grid_size[2] = vscreen->caps.caps.v2.max_compute_grid_size[2]; | |||
} | |||
return 3 * sizeof(uint64_t) ; | |||
case PIPE_COMPUTE_CAP_MAX_BLOCK_SIZE: | |||
if (ret) { | |||
uint64_t *block_size = ret; | |||
block_size[0] = vscreen->caps.caps.v2.max_compute_block_size[0]; | |||
block_size[1] = vscreen->caps.caps.v2.max_compute_block_size[1]; | |||
block_size[2] = vscreen->caps.caps.v2.max_compute_block_size[2]; | |||
} | |||
return 3 * sizeof(uint64_t); | |||
case PIPE_COMPUTE_CAP_MAX_THREADS_PER_BLOCK: | |||
if (ret) { | |||
uint64_t *max_threads_per_block = ret; | |||
*max_threads_per_block = vscreen->caps.caps.v2.max_compute_work_group_invocations; | |||
} | |||
return sizeof(uint64_t); | |||
case PIPE_COMPUTE_CAP_MAX_LOCAL_SIZE: | |||
if (ret) { | |||
uint64_t *max_local_size = ret; | |||
/* Value reported by the closed source driver. */ | |||
*max_local_size = vscreen->caps.caps.v2.max_compute_shared_memory_size; | |||
} | |||
return sizeof(uint64_t); | |||
default: | |||
break; | |||
} | |||
return 0; | |||
} | |||
static boolean | |||
virgl_is_vertex_format_supported(struct pipe_screen *screen, | |||
enum pipe_format format) | |||
@@ -666,6 +718,7 @@ virgl_create_screen(struct virgl_winsys *vws) | |||
screen->base.get_vendor = virgl_get_vendor; | |||
screen->base.get_param = virgl_get_param; | |||
screen->base.get_shader_param = virgl_get_shader_param; | |||
screen->base.get_compute_param = virgl_get_compute_param; | |||
screen->base.get_paramf = virgl_get_paramf; | |||
screen->base.is_format_supported = virgl_is_format_supported; | |||
screen->base.destroy = virgl_destroy_screen; |
@@ -138,5 +138,7 @@ static inline void virgl_ws_fill_new_caps_defaults(struct virgl_drm_caps *caps) | |||
caps->caps.v2.capability_bits = 0; | |||
caps->caps.v2.max_vertex_attrib_stride = 0; | |||
caps->caps.v2.max_image_samples = 0; | |||
caps->caps.v2.max_compute_work_group_invocations = 0; | |||
caps->caps.v2.max_compute_shared_memory_size = 0; | |||
} | |||
#endif |