X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fgallium%2Fdrivers%2Fr600%2Fr600_pipe.c;h=97c6808260d75f44092a97eda3dea9e0ebefbb67;hb=14bd9d764802b5fedb652c791faafe4d13b65262;hp=3564539843762037f05a8bcd7e9a94add86f460d;hpb=8ad9d83fdfc609303cebba3d811064b91aed6b0b;p=mesa.git diff --git a/src/gallium/drivers/r600/r600_pipe.c b/src/gallium/drivers/r600/r600_pipe.c index 35645398437..97c6808260d 100644 --- a/src/gallium/drivers/r600/r600_pipe.c +++ b/src/gallium/drivers/r600/r600_pipe.c @@ -22,76 +22,189 @@ */ #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "pipe/p_defines.h" +#include "pipe/p_state.h" +#include "pipe/p_context.h" +#include "tgsi/tgsi_scan.h" +#include "tgsi/tgsi_parse.h" +#include "tgsi/tgsi_util.h" +#include "util/u_blitter.h" +#include "util/u_double_list.h" +#include "util/u_format.h" +#include "util/u_format_s3tc.h" +#include "util/u_transfer.h" +#include "util/u_surface.h" +#include "util/u_pack_color.h" +#include "util/u_memory.h" +#include "util/u_inlines.h" +#include "util/u_upload_mgr.h" +#include "vl/vl_decoder.h" +#include "vl/vl_video_buffer.h" +#include "os/os_time.h" +#include "pipebuffer/pb_buffer.h" #include "r600.h" #include "r600d.h" #include "r600_resource.h" #include "r600_shader.h" #include "r600_pipe.h" -#include "r600_state_inlines.h" /* * pipe_context */ -static void r600_flush(struct pipe_context *ctx, unsigned flags, - struct pipe_fence_handle **fence) +static struct r600_fence *r600_create_fence(struct r600_pipe_context *ctx) +{ + struct r600_fence *fence = NULL; + + if (!ctx->fences.bo) { + /* Create the shared buffer object */ + ctx->fences.bo = (struct r600_resource*) + pipe_buffer_create(&ctx->screen->screen, PIPE_BIND_CUSTOM, + PIPE_USAGE_STAGING, 4096); + if (!ctx->fences.bo) { + R600_ERR("r600: failed to create bo for fence objects\n"); + return NULL; + } + ctx->fences.data = ctx->ws->buffer_map(ctx->fences.bo->buf, ctx->ctx.cs, + PIPE_TRANSFER_WRITE); + } + + if (!LIST_IS_EMPTY(&ctx->fences.pool)) { + struct r600_fence *entry; + + /* Try to find a freed fence that has been signalled */ + LIST_FOR_EACH_ENTRY(entry, &ctx->fences.pool, head) { + if (ctx->fences.data[entry->index] != 0) { + LIST_DELINIT(&entry->head); + fence = entry; + break; + } + } + } + + if (!fence) { + /* Allocate a new fence */ + struct r600_fence_block *block; + unsigned index; + + if ((ctx->fences.next_index + 1) >= 1024) { + R600_ERR("r600: too many concurrent fences\n"); + return NULL; + } + + index = ctx->fences.next_index++; + + if (!(index % FENCE_BLOCK_SIZE)) { + /* Allocate a new block */ + block = CALLOC_STRUCT(r600_fence_block); + if (block == NULL) + return NULL; + + LIST_ADD(&block->head, &ctx->fences.blocks); + } else { + block = LIST_ENTRY(struct r600_fence_block, ctx->fences.blocks.next, head); + } + + fence = &block->fences[index % FENCE_BLOCK_SIZE]; + fence->ctx = ctx; + fence->index = index; + } + + pipe_reference_init(&fence->reference, 1); + + ctx->fences.data[fence->index] = 0; + r600_context_emit_fence(&ctx->ctx, ctx->fences.bo, fence->index, 1); + return fence; +} + + +void r600_flush(struct pipe_context *ctx, struct pipe_fence_handle **fence, + unsigned flags) { struct r600_pipe_context *rctx = (struct r600_pipe_context *)ctx; -#if 0 - static int dc = 0; - char dname[256]; -#endif + struct r600_fence **rfence = (struct r600_fence**)fence; + struct pipe_query *render_cond = NULL; + unsigned render_cond_mode = 0; + + if (rfence) + *rfence = r600_create_fence(rctx); + + /* Disable render condition. */ + if (rctx->current_render_cond) { + render_cond = rctx->current_render_cond; + render_cond_mode = rctx->current_render_cond_mode; + ctx->render_condition(ctx, NULL, 0); + } - if (!rctx->ctx.pm4_cdwords) - return; + r600_context_flush(&rctx->ctx, flags); + + /* Re-enable render condition. */ + if (render_cond) { + ctx->render_condition(ctx, render_cond, render_cond_mode); + } +} + +static void r600_flush_from_st(struct pipe_context *ctx, + struct pipe_fence_handle **fence) +{ + r600_flush(ctx, fence, 0); +} - u_upload_flush(rctx->upload_vb); - u_upload_flush(rctx->upload_ib); +static void r600_flush_from_winsys(void *ctx, unsigned flags) +{ + r600_flush((struct pipe_context*)ctx, NULL, flags); +} -#if 0 - sprintf(dname, "gallium-%08d.bof", dc); - if (dc < 20) { - r600_context_dump_bof(&rctx->ctx, dname); - R600_ERR("dumped %s\n", dname); +static void r600_update_num_contexts(struct r600_screen *rscreen, int diff) +{ + pipe_mutex_lock(rscreen->mutex_num_contexts); + if (diff > 0) { + rscreen->num_contexts++; + + if (rscreen->num_contexts > 1) + util_slab_set_thread_safety(&rscreen->pool_buffers, + UTIL_SLAB_MULTITHREADED); + } else { + rscreen->num_contexts--; + + if (rscreen->num_contexts <= 1) + util_slab_set_thread_safety(&rscreen->pool_buffers, + UTIL_SLAB_SINGLETHREADED); } - dc++; -#endif - r600_context_flush(&rctx->ctx); + pipe_mutex_unlock(rscreen->mutex_num_contexts); } static void r600_destroy_context(struct pipe_context *context) { struct r600_pipe_context *rctx = (struct r600_pipe_context *)context; + rctx->context.delete_depth_stencil_alpha_state(&rctx->context, rctx->custom_dsa_flush); + util_unreference_framebuffer_state(&rctx->framebuffer); + r600_context_fini(&rctx->ctx); + + util_blitter_destroy(rctx->blitter); + for (int i = 0; i < R600_PIPE_NSTATES; i++) { free(rctx->states[i]); } - util_blitter_destroy(rctx->blitter); + u_vbuf_destroy(rctx->vbuf_mgr); + util_slab_destroy(&rctx->pool_transfers); + + if (rctx->fences.bo) { + struct r600_fence_block *entry, *tmp; - u_upload_destroy(rctx->upload_vb); - u_upload_destroy(rctx->upload_ib); + LIST_FOR_EACH_ENTRY_SAFE(entry, tmp, &rctx->fences.blocks, head) { + LIST_DEL(&entry->head); + FREE(entry); + } + + rctx->ws->buffer_unmap(rctx->fences.bo->buf); + pipe_resource_reference((struct pipe_resource**)&rctx->fences.bo, NULL); + } - if (rctx->tran.translate_cache) - translate_cache_destroy(rctx->tran.translate_cache); + r600_update_num_contexts(rctx->screen, -1); - FREE(rctx->ps_resource); - FREE(rctx->vs_resource); FREE(rctx); } @@ -99,110 +212,92 @@ static struct pipe_context *r600_create_context(struct pipe_screen *screen, void { struct r600_pipe_context *rctx = CALLOC_STRUCT(r600_pipe_context); struct r600_screen* rscreen = (struct r600_screen *)screen; - enum chip_class class; if (rctx == NULL) return NULL; + + r600_update_num_contexts(rscreen, 1); + rctx->context.winsys = rscreen->screen.winsys; rctx->context.screen = screen; rctx->context.priv = priv; rctx->context.destroy = r600_destroy_context; - rctx->context.flush = r600_flush; + rctx->context.flush = r600_flush_from_st; /* Easy accessing of screen/winsys. */ rctx->screen = rscreen; - rctx->radeon = rscreen->radeon; - rctx->family = r600_get_family(rctx->radeon); + rctx->ws = rscreen->ws; + rctx->family = rscreen->family; + rctx->chip_class = rscreen->chip_class; + + rctx->fences.bo = NULL; + rctx->fences.data = NULL; + rctx->fences.next_index = 0; + LIST_INITHEAD(&rctx->fences.pool); + LIST_INITHEAD(&rctx->fences.blocks); r600_init_blit_functions(rctx); r600_init_query_functions(rctx); r600_init_context_resource_functions(rctx); + r600_init_surface_functions(rctx); + rctx->context.draw_vbo = r600_draw_vbo; - switch (r600_get_family(rctx->radeon)) { - case CHIP_R600: - case CHIP_RV610: - case CHIP_RV630: - case CHIP_RV670: - case CHIP_RV620: - case CHIP_RV635: - case CHIP_RS780: - case CHIP_RS880: - case CHIP_RV770: - case CHIP_RV730: - case CHIP_RV710: - case CHIP_RV740: - rctx->context.draw_vbo = r600_draw_vbo; + rctx->context.create_video_decoder = vl_create_decoder; + rctx->context.create_video_buffer = vl_video_buffer_create; + + switch (rctx->chip_class) { + case R600: + case R700: r600_init_state_functions(rctx); - if (r600_context_init(&rctx->ctx, rctx->radeon)) { + if (r600_context_init(&rctx->ctx, rctx->screen)) { r600_destroy_context(&rctx->context); return NULL; } r600_init_config(rctx); + rctx->custom_dsa_flush = r600_create_db_flush_dsa(rctx); break; - case CHIP_CEDAR: - case CHIP_REDWOOD: - case CHIP_JUNIPER: - case CHIP_CYPRESS: - case CHIP_HEMLOCK: - rctx->context.draw_vbo = evergreen_draw; + case EVERGREEN: + case CAYMAN: evergreen_init_state_functions(rctx); - if (evergreen_context_init(&rctx->ctx, rctx->radeon)) { + if (evergreen_context_init(&rctx->ctx, rctx->screen)) { r600_destroy_context(&rctx->context); return NULL; } evergreen_init_config(rctx); + rctx->custom_dsa_flush = evergreen_create_db_flush_dsa(rctx); break; default: - R600_ERR("unsupported family %d\n", r600_get_family(rctx->radeon)); + R600_ERR("Unsupported chip class %d.\n", rctx->chip_class); r600_destroy_context(&rctx->context); return NULL; } - rctx->upload_ib = u_upload_create(&rctx->context, 32 * 1024, 16, - PIPE_BIND_INDEX_BUFFER); - if (rctx->upload_ib == NULL) { - r600_destroy_context(&rctx->context); - return NULL; - } + rctx->ctx.pipe = &rctx->context; + rctx->ctx.flush = r600_flush_from_winsys; + rctx->ws->cs_set_flush_callback(rctx->ctx.cs, r600_flush_from_winsys, rctx); - rctx->upload_vb = u_upload_create(&rctx->context, 128 * 1024, 16, - PIPE_BIND_VERTEX_BUFFER); - if (rctx->upload_vb == NULL) { + util_slab_create(&rctx->pool_transfers, + sizeof(struct pipe_transfer), 64, + UTIL_SLAB_SINGLETHREADED); + + rctx->vbuf_mgr = u_vbuf_create(&rctx->context, 1024 * 1024, 256, + PIPE_BIND_VERTEX_BUFFER | + PIPE_BIND_INDEX_BUFFER | + PIPE_BIND_CONSTANT_BUFFER, + U_VERTEX_FETCH_DWORD_ALIGNED); + if (!rctx->vbuf_mgr) { r600_destroy_context(&rctx->context); return NULL; } + rctx->vbuf_mgr->caps.format_fixed32 = 0; rctx->blitter = util_blitter_create(&rctx->context); if (rctx->blitter == NULL) { - FREE(rctx); - return NULL; - } - - rctx->tran.translate_cache = translate_cache_create(); - if (rctx->tran.translate_cache == NULL) { - FREE(rctx); - return NULL; - } - - rctx->vs_resource = CALLOC(R600_RESOURCE_ARRAY_SIZE, sizeof(struct r600_pipe_state)); - if (!rctx->vs_resource) { - FREE(rctx); - return NULL; - } - - rctx->ps_resource = CALLOC(R600_RESOURCE_ARRAY_SIZE, sizeof(struct r600_pipe_state)); - if (!rctx->ps_resource) { - FREE(rctx); + r600_destroy_context(&rctx->context); return NULL; } - class = r600_get_family_class(rctx->radeon); - if (class == R600 || class == R700) - rctx->custom_dsa_flush = r600_create_db_flush_dsa(rctx); - else - rctx->custom_dsa_flush = evergreen_create_db_flush_dsa(rctx); - - r600_blit_uncompress_depth_ptr = r600_blit_uncompress_depth; + r600_get_backend_mask(&rctx->ctx); /* this emits commands and must be last */ return &rctx->context; } @@ -218,115 +313,158 @@ static const char* r600_get_vendor(struct pipe_screen* pscreen) static const char *r600_get_family_name(enum radeon_family family) { switch(family) { - case CHIP_R600: return "R600"; - case CHIP_RV610: return "RV610"; - case CHIP_RV630: return "RV630"; - case CHIP_RV670: return "RV670"; - case CHIP_RV620: return "RV620"; - case CHIP_RV635: return "RV635"; - case CHIP_RS780: return "RS780"; - case CHIP_RS880: return "RS880"; - case CHIP_RV770: return "RV770"; - case CHIP_RV730: return "RV730"; - case CHIP_RV710: return "RV710"; - case CHIP_RV740: return "RV740"; - case CHIP_CEDAR: return "CEDAR"; - case CHIP_REDWOOD: return "REDWOOD"; - case CHIP_JUNIPER: return "JUNIPER"; - case CHIP_CYPRESS: return "CYPRESS"; - case CHIP_HEMLOCK: return "HEMLOCK"; - default: return "unknown"; + case CHIP_R600: return "AMD R600"; + case CHIP_RV610: return "AMD RV610"; + case CHIP_RV630: return "AMD RV630"; + case CHIP_RV670: return "AMD RV670"; + case CHIP_RV620: return "AMD RV620"; + case CHIP_RV635: return "AMD RV635"; + case CHIP_RS780: return "AMD RS780"; + case CHIP_RS880: return "AMD RS880"; + case CHIP_RV770: return "AMD RV770"; + case CHIP_RV730: return "AMD RV730"; + case CHIP_RV710: return "AMD RV710"; + case CHIP_RV740: return "AMD RV740"; + case CHIP_CEDAR: return "AMD CEDAR"; + case CHIP_REDWOOD: return "AMD REDWOOD"; + case CHIP_JUNIPER: return "AMD JUNIPER"; + case CHIP_CYPRESS: return "AMD CYPRESS"; + case CHIP_HEMLOCK: return "AMD HEMLOCK"; + case CHIP_PALM: return "AMD PALM"; + case CHIP_SUMO: return "AMD SUMO"; + case CHIP_SUMO2: return "AMD SUMO2"; + case CHIP_BARTS: return "AMD BARTS"; + case CHIP_TURKS: return "AMD TURKS"; + case CHIP_CAICOS: return "AMD CAICOS"; + case CHIP_CAYMAN: return "AMD CAYMAN"; + default: return "AMD unknown"; } } static const char* r600_get_name(struct pipe_screen* pscreen) { struct r600_screen *rscreen = (struct r600_screen *)pscreen; - enum radeon_family family = r600_get_family(rscreen->radeon); - return r600_get_family_name(family); + return r600_get_family_name(rscreen->family); } static int r600_get_param(struct pipe_screen* pscreen, enum pipe_cap param) { + struct r600_screen *rscreen = (struct r600_screen *)pscreen; + enum radeon_family family = rscreen->family; + switch (param) { /* Supported features (boolean caps). */ case PIPE_CAP_NPOT_TEXTURES: case PIPE_CAP_TWO_SIDED_STENCIL: - case PIPE_CAP_GLSL: case PIPE_CAP_DUAL_SOURCE_BLEND: case PIPE_CAP_ANISOTROPIC_FILTER: case PIPE_CAP_POINT_SPRITE: case PIPE_CAP_OCCLUSION_QUERY: case PIPE_CAP_TEXTURE_SHADOW_MAP: case PIPE_CAP_TEXTURE_MIRROR_CLAMP: - case PIPE_CAP_TEXTURE_MIRROR_REPEAT: case PIPE_CAP_BLEND_EQUATION_SEPARATE: - case PIPE_CAP_SM3: case PIPE_CAP_TEXTURE_SWIZZLE: - case PIPE_CAP_INDEP_BLEND_ENABLE: case PIPE_CAP_DEPTHSTENCIL_CLEAR_SEPARATE: case PIPE_CAP_DEPTH_CLAMP: case PIPE_CAP_SHADER_STENCIL_EXPORT: + case PIPE_CAP_VERTEX_ELEMENT_INSTANCE_DIVISOR: + case PIPE_CAP_MIXED_COLORBUFFER_FORMATS: + case PIPE_CAP_TGSI_FS_COORD_ORIGIN_UPPER_LEFT: + case PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_HALF_INTEGER: + case PIPE_CAP_SM3: + case PIPE_CAP_SEAMLESS_CUBE_MAP: + case PIPE_CAP_FRAGMENT_COLOR_CLAMP_CONTROL: + case PIPE_CAP_PRIMITIVE_RESTART: + case PIPE_CAP_CONDITIONAL_RENDER: + case PIPE_CAP_TEXTURE_BARRIER: return 1; - /* Unsupported features (boolean caps). */ - case PIPE_CAP_TIMER_QUERY: - case PIPE_CAP_STREAM_OUTPUT: - case PIPE_CAP_INDEP_BLEND_FUNC: /* FIXME allow this */ + /* Supported except the original R600. */ + case PIPE_CAP_INDEP_BLEND_ENABLE: + case PIPE_CAP_INDEP_BLEND_FUNC: + /* R600 doesn't support per-MRT blends */ + return family == CHIP_R600 ? 0 : 1; + + /* Supported on Evergreen. */ + case PIPE_CAP_SEAMLESS_CUBE_MAP_PER_TEXTURE: + return family >= CHIP_CEDAR ? 1 : 0; + + /* Unsupported features. */ + case PIPE_CAP_MAX_STREAM_OUTPUT_BUFFERS: + case PIPE_CAP_MAX_STREAM_OUTPUT_SEPARATE_ATTRIBS: + case PIPE_CAP_MAX_STREAM_OUTPUT_SEPARATE_COMPONENTS: + case PIPE_CAP_MAX_STREAM_OUTPUT_INTERLEAVED_COMPONENTS: + case PIPE_CAP_STREAM_OUTPUT_PAUSE_RESUME: + case PIPE_CAP_TGSI_INSTANCEID: + case PIPE_CAP_TGSI_FS_COORD_ORIGIN_LOWER_LEFT: + case PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_INTEGER: + case PIPE_CAP_SCALED_RESOLVE: return 0; /* Texturing. */ case PIPE_CAP_MAX_TEXTURE_2D_LEVELS: case PIPE_CAP_MAX_TEXTURE_3D_LEVELS: case PIPE_CAP_MAX_TEXTURE_CUBE_LEVELS: - return 14; - case PIPE_CAP_MAX_VERTEX_TEXTURE_UNITS: - /* FIXME allow this once infrastructure is there */ - return 16; - case PIPE_CAP_MAX_TEXTURE_IMAGE_UNITS: + if (family >= CHIP_CEDAR) + return 15; + else + return 14; + case PIPE_CAP_MAX_TEXTURE_ARRAY_LAYERS: + return rscreen->info.drm_minor >= 9 ? + (family >= CHIP_CEDAR ? 16384 : 8192) : 0; case PIPE_CAP_MAX_COMBINED_SAMPLERS: - return 16; + return 32; /* Render targets. */ case PIPE_CAP_MAX_RENDER_TARGETS: /* FIXME some r6xx are buggy and can only do 4 */ return 8; - /* Fragment coordinate conventions. */ - case PIPE_CAP_TGSI_FS_COORD_ORIGIN_UPPER_LEFT: - case PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_HALF_INTEGER: - return 1; - case PIPE_CAP_TGSI_FS_COORD_ORIGIN_LOWER_LEFT: - case PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_INTEGER: - return 0; + /* Timer queries, present when the clock frequency is non zero. */ + case PIPE_CAP_TIMER_QUERY: + return rscreen->info.r600_clock_crystal_freq != 0; - default: - R600_ERR("r600: unknown param %d\n", param); - return 0; + case PIPE_CAP_MIN_TEXEL_OFFSET: + return -8; + + case PIPE_CAP_MAX_TEXEL_OFFSET: + return 7; } + return 0; } -static float r600_get_paramf(struct pipe_screen* pscreen, enum pipe_cap param) +static float r600_get_paramf(struct pipe_screen* pscreen, + enum pipe_capf param) { + struct r600_screen *rscreen = (struct r600_screen *)pscreen; + enum radeon_family family = rscreen->family; + switch (param) { - case PIPE_CAP_MAX_LINE_WIDTH: - case PIPE_CAP_MAX_LINE_WIDTH_AA: - case PIPE_CAP_MAX_POINT_WIDTH: - case PIPE_CAP_MAX_POINT_WIDTH_AA: - return 8192.0f; - case PIPE_CAP_MAX_TEXTURE_ANISOTROPY: + case PIPE_CAPF_MAX_LINE_WIDTH: + case PIPE_CAPF_MAX_LINE_WIDTH_AA: + case PIPE_CAPF_MAX_POINT_WIDTH: + case PIPE_CAPF_MAX_POINT_WIDTH_AA: + if (family >= CHIP_CEDAR) + return 16384.0f; + else + return 8192.0f; + case PIPE_CAPF_MAX_TEXTURE_ANISOTROPY: return 16.0f; - case PIPE_CAP_MAX_TEXTURE_LOD_BIAS: + case PIPE_CAPF_MAX_TEXTURE_LOD_BIAS: return 16.0f; - default: - R600_ERR("r600: unsupported paramf %d\n", param); + case PIPE_CAPF_GUARD_BAND_LEFT: + case PIPE_CAPF_GUARD_BAND_TOP: + case PIPE_CAPF_GUARD_BAND_RIGHT: + case PIPE_CAPF_GUARD_BAND_BOTTOM: return 0.0f; } + return 0.0f; } static int r600_get_shader_param(struct pipe_screen* pscreen, unsigned shader, enum pipe_shader_cap param) { + struct r600_screen *rscreen = (struct r600_screen *)pscreen; switch(shader) { case PIPE_SHADER_FRAGMENT: @@ -351,110 +489,312 @@ static int r600_get_shader_param(struct pipe_screen* pscreen, unsigned shader, e return 8; /* FIXME */ case PIPE_SHADER_CAP_MAX_INPUTS: if(shader == PIPE_SHADER_FRAGMENT) - return 10; + return 34; else - return 16; + return 32; case PIPE_SHADER_CAP_MAX_TEMPS: - return 256; //max native temporaries + return 256; /* Max native temporaries. */ case PIPE_SHADER_CAP_MAX_ADDRS: - return 1; //max native address registers/* FIXME Isn't this equal to TEMPS? */ + /* FIXME Isn't this equal to TEMPS? */ + return 1; /* Max native address registers */ case PIPE_SHADER_CAP_MAX_CONSTS: - return 256; //max native parameters + return R600_MAX_CONST_BUFFER_SIZE; case PIPE_SHADER_CAP_MAX_CONST_BUFFERS: - return 1; + return R600_MAX_CONST_BUFFERS; case PIPE_SHADER_CAP_MAX_PREDS: return 0; /* FIXME */ case PIPE_SHADER_CAP_TGSI_CONT_SUPPORTED: return 1; - default: + case PIPE_SHADER_CAP_INDIRECT_INPUT_ADDR: + case PIPE_SHADER_CAP_INDIRECT_OUTPUT_ADDR: + case PIPE_SHADER_CAP_INDIRECT_TEMP_ADDR: + case PIPE_SHADER_CAP_INDIRECT_CONST_ADDR: + return 1; + case PIPE_SHADER_CAP_SUBROUTINES: return 0; + case PIPE_SHADER_CAP_INTEGERS: + if (rscreen->chip_class == EVERGREEN) + return 1; + return 0; + case PIPE_SHADER_CAP_MAX_TEXTURE_SAMPLERS: + return 16; + case PIPE_SHADER_CAP_OUTPUT_READ: + return 1; } + return 0; } -static boolean r600_is_format_supported(struct pipe_screen* screen, - enum pipe_format format, - enum pipe_texture_target target, - unsigned sample_count, - unsigned usage, - unsigned geom_flags) +static int r600_get_video_param(struct pipe_screen *screen, + enum pipe_video_profile profile, + enum pipe_video_cap param) { - unsigned retval = 0; - if (target >= PIPE_MAX_TEXTURE_TYPES) { - R600_ERR("r600: unsupported texture type %d\n", target); - return FALSE; + switch (param) { + case PIPE_VIDEO_CAP_SUPPORTED: + return vl_profile_supported(screen, profile); + case PIPE_VIDEO_CAP_NPOT_TEXTURES: + return 1; + case PIPE_VIDEO_CAP_MAX_WIDTH: + case PIPE_VIDEO_CAP_MAX_HEIGHT: + return vl_video_buffer_max_size(screen); + case PIPE_VIDEO_CAP_NUM_BUFFERS_DESIRED: + return vl_num_buffers_desired(screen, profile); + default: + return 0; } +} + +static void r600_destroy_screen(struct pipe_screen* pscreen) +{ + struct r600_screen *rscreen = (struct r600_screen *)pscreen; + + if (rscreen == NULL) + return; - /* Multisample */ - if (sample_count > 1) - return FALSE; + rscreen->ws->destroy(rscreen->ws); - if ((usage & PIPE_BIND_SAMPLER_VIEW) && - r600_is_sampler_format_supported(format)) { - retval |= PIPE_BIND_SAMPLER_VIEW; + util_slab_destroy(&rscreen->pool_buffers); + pipe_mutex_destroy(rscreen->mutex_num_contexts); + FREE(rscreen); +} + +static void r600_fence_reference(struct pipe_screen *pscreen, + struct pipe_fence_handle **ptr, + struct pipe_fence_handle *fence) +{ + struct r600_fence **oldf = (struct r600_fence**)ptr; + struct r600_fence *newf = (struct r600_fence*)fence; + + if (pipe_reference(&(*oldf)->reference, &newf->reference)) { + struct r600_pipe_context *ctx = (*oldf)->ctx; + LIST_ADDTAIL(&(*oldf)->head, &ctx->fences.pool); } - if ((usage & (PIPE_BIND_RENDER_TARGET | - PIPE_BIND_DISPLAY_TARGET | - PIPE_BIND_SCANOUT | - PIPE_BIND_SHARED)) && - r600_is_colorbuffer_format_supported(format)) { - retval |= usage & - (PIPE_BIND_RENDER_TARGET | - PIPE_BIND_DISPLAY_TARGET | - PIPE_BIND_SCANOUT | - PIPE_BIND_SHARED); + *ptr = fence; +} + +static boolean r600_fence_signalled(struct pipe_screen *pscreen, + struct pipe_fence_handle *fence) +{ + struct r600_fence *rfence = (struct r600_fence*)fence; + struct r600_pipe_context *ctx = rfence->ctx; + + return ctx->fences.data[rfence->index]; +} + +static boolean r600_fence_finish(struct pipe_screen *pscreen, + struct pipe_fence_handle *fence, + uint64_t timeout) +{ + struct r600_fence *rfence = (struct r600_fence*)fence; + struct r600_pipe_context *ctx = rfence->ctx; + int64_t start_time = 0; + unsigned spins = 0; + + if (timeout != PIPE_TIMEOUT_INFINITE) { + start_time = os_time_get(); + + /* Convert to microseconds. */ + timeout /= 1000; } - if ((usage & PIPE_BIND_DEPTH_STENCIL) && - r600_is_zs_format_supported(format)) { - retval |= PIPE_BIND_DEPTH_STENCIL; + while (ctx->fences.data[rfence->index] == 0) { + if (++spins % 256) + continue; +#ifdef PIPE_OS_UNIX + sched_yield(); +#else + os_time_sleep(10); +#endif + if (timeout != PIPE_TIMEOUT_INFINITE && + os_time_get() - start_time >= timeout) { + return FALSE; + } } - if ((usage & PIPE_BIND_VERTEX_BUFFER) && - r600_is_vertex_format_supported(format)) - retval |= PIPE_BIND_VERTEX_BUFFER; + return TRUE; +} + +static int r600_interpret_tiling(struct r600_screen *rscreen, uint32_t tiling_config) +{ + switch ((tiling_config & 0xe) >> 1) { + case 0: + rscreen->tiling_info.num_channels = 1; + break; + case 1: + rscreen->tiling_info.num_channels = 2; + break; + case 2: + rscreen->tiling_info.num_channels = 4; + break; + case 3: + rscreen->tiling_info.num_channels = 8; + break; + default: + return -EINVAL; + } - if (usage & PIPE_BIND_TRANSFER_READ) - retval |= PIPE_BIND_TRANSFER_READ; - if (usage & PIPE_BIND_TRANSFER_WRITE) - retval |= PIPE_BIND_TRANSFER_WRITE; + switch ((tiling_config & 0x30) >> 4) { + case 0: + rscreen->tiling_info.num_banks = 4; + break; + case 1: + rscreen->tiling_info.num_banks = 8; + break; + default: + return -EINVAL; - return retval == usage; + } + switch ((tiling_config & 0xc0) >> 6) { + case 0: + rscreen->tiling_info.group_bytes = 256; + break; + case 1: + rscreen->tiling_info.group_bytes = 512; + break; + default: + return -EINVAL; + } + return 0; } -static void r600_destroy_screen(struct pipe_screen* pscreen) +static int evergreen_interpret_tiling(struct r600_screen *rscreen, uint32_t tiling_config) { - struct r600_screen *rscreen = (struct r600_screen *)pscreen; + switch (tiling_config & 0xf) { + case 0: + rscreen->tiling_info.num_channels = 1; + break; + case 1: + rscreen->tiling_info.num_channels = 2; + break; + case 2: + rscreen->tiling_info.num_channels = 4; + break; + case 3: + rscreen->tiling_info.num_channels = 8; + break; + default: + return -EINVAL; + } - if (rscreen == NULL) - return; - FREE(rscreen); + switch ((tiling_config & 0xf0) >> 4) { + case 0: + rscreen->tiling_info.num_banks = 4; + break; + case 1: + rscreen->tiling_info.num_banks = 8; + break; + case 2: + rscreen->tiling_info.num_banks = 16; + break; + default: + return -EINVAL; + } + + switch ((tiling_config & 0xf00) >> 8) { + case 0: + rscreen->tiling_info.group_bytes = 256; + break; + case 1: + rscreen->tiling_info.group_bytes = 512; + break; + default: + return -EINVAL; + } + return 0; } +static int r600_init_tiling(struct r600_screen *rscreen) +{ + uint32_t tiling_config = rscreen->info.r600_tiling_config; + + /* set default group bytes, overridden by tiling info ioctl */ + if (rscreen->chip_class <= R700) { + rscreen->tiling_info.group_bytes = 256; + } else { + rscreen->tiling_info.group_bytes = 512; + } + + if (!tiling_config) + return 0; + + if (rscreen->chip_class <= R700) { + return r600_interpret_tiling(rscreen, tiling_config); + } else { + return evergreen_interpret_tiling(rscreen, tiling_config); + } +} -struct pipe_screen *r600_screen_create(struct radeon *radeon) +static unsigned radeon_family_from_device(unsigned device) { - struct r600_screen *rscreen; + switch (device) { +#define CHIPSET(pciid, name, family) case pciid: return CHIP_##family; +#include "pci_ids/r600_pci_ids.h" +#undef CHIPSET + default: + return CHIP_UNKNOWN; + } +} - rscreen = CALLOC_STRUCT(r600_screen); +struct pipe_screen *r600_screen_create(struct radeon_winsys *ws) +{ + struct r600_screen *rscreen = CALLOC_STRUCT(r600_screen); if (rscreen == NULL) { return NULL; } - rscreen->radeon = radeon; - rscreen->screen.winsys = (struct pipe_winsys*)radeon; + rscreen->ws = ws; + ws->query_info(ws, &rscreen->info); + + rscreen->family = radeon_family_from_device(rscreen->info.pci_id); + if (rscreen->family == CHIP_UNKNOWN) { + fprintf(stderr, "r600: Unknown chipset 0x%04X\n", rscreen->info.pci_id); + FREE(rscreen); + return NULL; + } + + /* setup class */ + if (rscreen->family == CHIP_CAYMAN) { + rscreen->chip_class = CAYMAN; + } else if (rscreen->family >= CHIP_CEDAR) { + rscreen->chip_class = EVERGREEN; + } else if (rscreen->family >= CHIP_RV770) { + rscreen->chip_class = R700; + } else { + rscreen->chip_class = R600; + } + + if (r600_init_tiling(rscreen)) { + FREE(rscreen); + return NULL; + } + + rscreen->screen.winsys = (struct pipe_winsys*)ws; rscreen->screen.destroy = r600_destroy_screen; rscreen->screen.get_name = r600_get_name; rscreen->screen.get_vendor = r600_get_vendor; rscreen->screen.get_param = r600_get_param; rscreen->screen.get_shader_param = r600_get_shader_param; rscreen->screen.get_paramf = r600_get_paramf; - rscreen->screen.is_format_supported = r600_is_format_supported; + rscreen->screen.get_video_param = r600_get_video_param; + if (rscreen->chip_class >= EVERGREEN) { + rscreen->screen.is_format_supported = evergreen_is_format_supported; + } else { + rscreen->screen.is_format_supported = r600_is_format_supported; + } + rscreen->screen.is_video_format_supported = vl_video_buffer_is_format_supported; rscreen->screen.context_create = r600_create_context; - r600_init_screen_texture_functions(&rscreen->screen); + rscreen->screen.fence_reference = r600_fence_reference; + rscreen->screen.fence_signalled = r600_fence_signalled; + rscreen->screen.fence_finish = r600_fence_finish; r600_init_screen_resource_functions(&rscreen->screen); - rscreen->tiling_info = r600_get_tiling_info(radeon); + util_format_s3tc_init(); + + util_slab_create(&rscreen->pool_buffers, + sizeof(struct r600_resource), 64, + UTIL_SLAB_SINGLETHREADED); + + pipe_mutex_init(rscreen->mutex_num_contexts); return &rscreen->screen; }