101e04c3fSmrg/* 201e04c3fSmrg * Copyright © 2014-2017 Broadcom 301e04c3fSmrg * 401e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a 501e04c3fSmrg * copy of this software and associated documentation files (the "Software"), 601e04c3fSmrg * to deal in the Software without restriction, including without limitation 701e04c3fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 801e04c3fSmrg * and/or sell copies of the Software, and to permit persons to whom the 901e04c3fSmrg * Software is furnished to do so, subject to the following conditions: 1001e04c3fSmrg * 1101e04c3fSmrg * The above copyright notice and this permission notice (including the next 1201e04c3fSmrg * paragraph) shall be included in all copies or substantial portions of the 1301e04c3fSmrg * Software. 1401e04c3fSmrg * 1501e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1601e04c3fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1701e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1801e04c3fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1901e04c3fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2001e04c3fSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 2101e04c3fSmrg * IN THE SOFTWARE. 2201e04c3fSmrg */ 2301e04c3fSmrg 2401e04c3fSmrg#include <xf86drm.h> 2501e04c3fSmrg#include <err.h> 2601e04c3fSmrg 2701e04c3fSmrg#include "pipe/p_defines.h" 2801e04c3fSmrg#include "util/hash_table.h" 2901e04c3fSmrg#include "util/ralloc.h" 3001e04c3fSmrg#include "util/u_inlines.h" 3101e04c3fSmrg#include "util/u_memory.h" 3201e04c3fSmrg#include "util/u_blitter.h" 3301e04c3fSmrg#include "util/u_upload_mgr.h" 347ec681f3Smrg#include "util/u_prim.h" 3501e04c3fSmrg#include "pipe/p_screen.h" 3601e04c3fSmrg 3701e04c3fSmrg#include "v3d_screen.h" 3801e04c3fSmrg#include "v3d_context.h" 3901e04c3fSmrg#include "v3d_resource.h" 409f464c52Smaya#include "broadcom/compiler/v3d_compiler.h" 4101e04c3fSmrg 4201e04c3fSmrgvoid 4301e04c3fSmrgv3d_flush(struct pipe_context *pctx) 4401e04c3fSmrg{ 4501e04c3fSmrg struct v3d_context *v3d = v3d_context(pctx); 4601e04c3fSmrg 4701e04c3fSmrg hash_table_foreach(v3d->jobs, entry) { 4801e04c3fSmrg struct v3d_job *job = entry->data; 4901e04c3fSmrg v3d_job_submit(v3d, job); 5001e04c3fSmrg } 5101e04c3fSmrg} 5201e04c3fSmrg 5301e04c3fSmrgstatic void 5401e04c3fSmrgv3d_pipe_flush(struct pipe_context *pctx, struct pipe_fence_handle **fence, 5501e04c3fSmrg unsigned flags) 5601e04c3fSmrg{ 5701e04c3fSmrg struct v3d_context *v3d = v3d_context(pctx); 5801e04c3fSmrg 5901e04c3fSmrg v3d_flush(pctx); 6001e04c3fSmrg 6101e04c3fSmrg if (fence) { 6201e04c3fSmrg struct pipe_screen *screen = pctx->screen; 6301e04c3fSmrg struct v3d_fence *f = v3d_fence_create(v3d); 6401e04c3fSmrg screen->fence_reference(screen, fence, NULL); 6501e04c3fSmrg *fence = (struct pipe_fence_handle *)f; 6601e04c3fSmrg } 6701e04c3fSmrg} 6801e04c3fSmrg 699f464c52Smayastatic void 709f464c52Smayav3d_memory_barrier(struct pipe_context *pctx, unsigned int flags) 719f464c52Smaya{ 729f464c52Smaya struct v3d_context *v3d = v3d_context(pctx); 739f464c52Smaya 747ec681f3Smrg /* We only need to flush for SSBOs and images, because for everything 757ec681f3Smrg * else we flush the job automatically when we needed. 767ec681f3Smrg */ 777ec681f3Smrg const unsigned int flush_flags = PIPE_BARRIER_SHADER_BUFFER | 787ec681f3Smrg PIPE_BARRIER_IMAGE; 797ec681f3Smrg 807ec681f3Smrg if (!(flags & flush_flags)) 819f464c52Smaya return; 829f464c52Smaya 839f464c52Smaya /* We only need to flush jobs writing to SSBOs/images. */ 849f464c52Smaya perf_debug("Flushing all jobs for glMemoryBarrier(), could do better"); 859f464c52Smaya v3d_flush(pctx); 869f464c52Smaya} 879f464c52Smaya 889f464c52Smayastatic void 899f464c52Smayav3d_set_debug_callback(struct pipe_context *pctx, 909f464c52Smaya const struct pipe_debug_callback *cb) 919f464c52Smaya{ 929f464c52Smaya struct v3d_context *v3d = v3d_context(pctx); 939f464c52Smaya 949f464c52Smaya if (cb) 959f464c52Smaya v3d->debug = *cb; 969f464c52Smaya else 979f464c52Smaya memset(&v3d->debug, 0, sizeof(v3d->debug)); 989f464c52Smaya} 999f464c52Smaya 10001e04c3fSmrgstatic void 10101e04c3fSmrgv3d_invalidate_resource(struct pipe_context *pctx, struct pipe_resource *prsc) 10201e04c3fSmrg{ 10301e04c3fSmrg struct v3d_context *v3d = v3d_context(pctx); 10401e04c3fSmrg struct v3d_resource *rsc = v3d_resource(prsc); 10501e04c3fSmrg 10601e04c3fSmrg rsc->initialized_buffers = 0; 10701e04c3fSmrg 10801e04c3fSmrg struct hash_entry *entry = _mesa_hash_table_search(v3d->write_jobs, 10901e04c3fSmrg prsc); 11001e04c3fSmrg if (!entry) 11101e04c3fSmrg return; 11201e04c3fSmrg 11301e04c3fSmrg struct v3d_job *job = entry->data; 11401e04c3fSmrg if (job->key.zsbuf && job->key.zsbuf->texture == prsc) 11501e04c3fSmrg job->store &= ~(PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL); 11601e04c3fSmrg} 11701e04c3fSmrg 1187ec681f3Smrg/** 1197ec681f3Smrg * Flushes the current job to get up-to-date primitive counts written to the 1207ec681f3Smrg * primitive counts BO, then accumulates the transform feedback primitive count 1217ec681f3Smrg * in the context and the corresponding vertex counts in the bound stream 1227ec681f3Smrg * output targets. 1237ec681f3Smrg */ 1247ec681f3Smrgvoid 1257ec681f3Smrgv3d_update_primitive_counters(struct v3d_context *v3d) 1267ec681f3Smrg{ 1277ec681f3Smrg struct v3d_job *job = v3d_get_job_for_fbo(v3d); 1287ec681f3Smrg if (job->draw_calls_queued == 0) 1297ec681f3Smrg return; 1307ec681f3Smrg 1317ec681f3Smrg /* In order to get up-to-date primitive counts we need to submit 1327ec681f3Smrg * the job for execution so we get the counts written to memory. 1337ec681f3Smrg * Notice that this will require a sync wait for the buffer write. 1347ec681f3Smrg */ 1357ec681f3Smrg uint32_t prims_before = v3d->tf_prims_generated; 1367ec681f3Smrg v3d_job_submit(v3d, job); 1377ec681f3Smrg uint32_t prims_after = v3d->tf_prims_generated; 1387ec681f3Smrg if (prims_before == prims_after) 1397ec681f3Smrg return; 1407ec681f3Smrg 1417ec681f3Smrg enum pipe_prim_type prim_type = u_base_prim_type(v3d->prim_mode); 1427ec681f3Smrg uint32_t num_verts = u_vertices_for_prims(prim_type, 1437ec681f3Smrg prims_after - prims_before); 1447ec681f3Smrg for (int i = 0; i < v3d->streamout.num_targets; i++) { 1457ec681f3Smrg struct v3d_stream_output_target *so = 1467ec681f3Smrg v3d_stream_output_target(v3d->streamout.targets[i]); 1477ec681f3Smrg so->recorded_vertex_count += num_verts; 1487ec681f3Smrg } 1497ec681f3Smrg} 1507ec681f3Smrg 1517ec681f3Smrgbool 1527ec681f3Smrgv3d_line_smoothing_enabled(struct v3d_context *v3d) 1537ec681f3Smrg{ 1547ec681f3Smrg if (!v3d->rasterizer->base.line_smooth) 1557ec681f3Smrg return false; 1567ec681f3Smrg 1577ec681f3Smrg /* According to the OpenGL docs, line smoothing shouldn’t be applied 1587ec681f3Smrg * when multisampling 1597ec681f3Smrg */ 1607ec681f3Smrg if (v3d->job->msaa || v3d->rasterizer->base.multisample) 1617ec681f3Smrg return false; 1627ec681f3Smrg 1637ec681f3Smrg if (v3d->framebuffer.nr_cbufs <= 0) 1647ec681f3Smrg return false; 1657ec681f3Smrg 1667ec681f3Smrg struct pipe_surface *cbuf = v3d->framebuffer.cbufs[0]; 1677ec681f3Smrg if (!cbuf) 1687ec681f3Smrg return false; 1697ec681f3Smrg 1707ec681f3Smrg /* Modifying the alpha for pure integer formats probably 1717ec681f3Smrg * doesn’t make sense because we don’t know how the application 1727ec681f3Smrg * uses the alpha value. 1737ec681f3Smrg */ 1747ec681f3Smrg if (util_format_is_pure_integer(cbuf->format)) 1757ec681f3Smrg return false; 1767ec681f3Smrg 1777ec681f3Smrg return true; 1787ec681f3Smrg} 1797ec681f3Smrg 1807ec681f3Smrgfloat 1817ec681f3Smrgv3d_get_real_line_width(struct v3d_context *v3d) 1827ec681f3Smrg{ 1837ec681f3Smrg float width = v3d->rasterizer->base.line_width; 1847ec681f3Smrg 1857ec681f3Smrg if (v3d_line_smoothing_enabled(v3d)) { 1867ec681f3Smrg /* If line smoothing is enabled then we want to add some extra 1877ec681f3Smrg * pixels to the width in order to have some semi-transparent 1887ec681f3Smrg * edges. 1897ec681f3Smrg */ 1907ec681f3Smrg width = floorf(M_SQRT2 * width) + 3; 1917ec681f3Smrg } 1927ec681f3Smrg 1937ec681f3Smrg return width; 1947ec681f3Smrg} 1957ec681f3Smrg 1967ec681f3Smrgvoid 1977ec681f3Smrgv3d_ensure_prim_counts_allocated(struct v3d_context *ctx) 1987ec681f3Smrg{ 1997ec681f3Smrg if (ctx->prim_counts) 2007ec681f3Smrg return; 2017ec681f3Smrg 2027ec681f3Smrg /* Init all 7 counters and 1 padding to 0 */ 2037ec681f3Smrg uint32_t zeroes[8] = { 0 }; 2047ec681f3Smrg u_upload_data(ctx->uploader, 2057ec681f3Smrg 0, sizeof(zeroes), 32, zeroes, 2067ec681f3Smrg &ctx->prim_counts_offset, 2077ec681f3Smrg &ctx->prim_counts); 2087ec681f3Smrg} 2097ec681f3Smrg 2107ec681f3Smrgvoid 2117ec681f3Smrgv3d_flag_dirty_sampler_state(struct v3d_context *v3d, 2127ec681f3Smrg enum pipe_shader_type shader) 2137ec681f3Smrg{ 2147ec681f3Smrg switch (shader) { 2157ec681f3Smrg case PIPE_SHADER_VERTEX: 2167ec681f3Smrg v3d->dirty |= V3D_DIRTY_VERTTEX; 2177ec681f3Smrg break; 2187ec681f3Smrg case PIPE_SHADER_GEOMETRY: 2197ec681f3Smrg v3d->dirty |= V3D_DIRTY_GEOMTEX; 2207ec681f3Smrg break; 2217ec681f3Smrg case PIPE_SHADER_FRAGMENT: 2227ec681f3Smrg v3d->dirty |= V3D_DIRTY_FRAGTEX; 2237ec681f3Smrg break; 2247ec681f3Smrg case PIPE_SHADER_COMPUTE: 2257ec681f3Smrg v3d->dirty |= V3D_DIRTY_COMPTEX; 2267ec681f3Smrg break; 2277ec681f3Smrg default: 2287ec681f3Smrg unreachable("Unsupported shader stage"); 2297ec681f3Smrg } 2307ec681f3Smrg} 2317ec681f3Smrg 2327ec681f3Smrgvoid 2337ec681f3Smrgv3d_create_texture_shader_state_bo(struct v3d_context *v3d, 2347ec681f3Smrg struct v3d_sampler_view *so) 2357ec681f3Smrg{ 2367ec681f3Smrg if (v3d->screen->devinfo.ver >= 41) 2377ec681f3Smrg v3d41_create_texture_shader_state_bo(v3d, so); 2387ec681f3Smrg else 2397ec681f3Smrg v3d33_create_texture_shader_state_bo(v3d, so); 2407ec681f3Smrg} 2417ec681f3Smrg 2427ec681f3Smrgvoid 2437ec681f3Smrgv3d_get_tile_buffer_size(bool is_msaa, 2447ec681f3Smrg uint32_t nr_cbufs, 2457ec681f3Smrg struct pipe_surface **cbufs, 2467ec681f3Smrg struct pipe_surface *bbuf, 2477ec681f3Smrg uint32_t *tile_width, 2487ec681f3Smrg uint32_t *tile_height, 2497ec681f3Smrg uint32_t *max_bpp) 2507ec681f3Smrg{ 2517ec681f3Smrg static const uint8_t tile_sizes[] = { 2527ec681f3Smrg 64, 64, 2537ec681f3Smrg 64, 32, 2547ec681f3Smrg 32, 32, 2557ec681f3Smrg 32, 16, 2567ec681f3Smrg 16, 16, 2577ec681f3Smrg }; 2587ec681f3Smrg int tile_size_index = 0; 2597ec681f3Smrg if (is_msaa) 2607ec681f3Smrg tile_size_index += 2; 2617ec681f3Smrg 2627ec681f3Smrg if (cbufs[3] || cbufs[2]) 2637ec681f3Smrg tile_size_index += 2; 2647ec681f3Smrg else if (cbufs[1]) 2657ec681f3Smrg tile_size_index++; 2667ec681f3Smrg 2677ec681f3Smrg *max_bpp = 0; 2687ec681f3Smrg for (int i = 0; i < nr_cbufs; i++) { 2697ec681f3Smrg if (cbufs[i]) { 2707ec681f3Smrg struct v3d_surface *surf = v3d_surface(cbufs[i]); 2717ec681f3Smrg *max_bpp = MAX2(*max_bpp, surf->internal_bpp); 2727ec681f3Smrg } 2737ec681f3Smrg } 2747ec681f3Smrg 2757ec681f3Smrg if (bbuf) { 2767ec681f3Smrg struct v3d_surface *bsurf = v3d_surface(bbuf); 2777ec681f3Smrg assert(bbuf->texture->nr_samples <= 1 || is_msaa); 2787ec681f3Smrg *max_bpp = MAX2(*max_bpp, bsurf->internal_bpp); 2797ec681f3Smrg } 2807ec681f3Smrg 2817ec681f3Smrg tile_size_index += *max_bpp; 2827ec681f3Smrg 2837ec681f3Smrg assert(tile_size_index < ARRAY_SIZE(tile_sizes)); 2847ec681f3Smrg *tile_width = tile_sizes[tile_size_index * 2 + 0]; 2857ec681f3Smrg *tile_height = tile_sizes[tile_size_index * 2 + 1]; 2867ec681f3Smrg} 2877ec681f3Smrg 28801e04c3fSmrgstatic void 28901e04c3fSmrgv3d_context_destroy(struct pipe_context *pctx) 29001e04c3fSmrg{ 29101e04c3fSmrg struct v3d_context *v3d = v3d_context(pctx); 29201e04c3fSmrg 29301e04c3fSmrg v3d_flush(pctx); 29401e04c3fSmrg 29501e04c3fSmrg if (v3d->blitter) 29601e04c3fSmrg util_blitter_destroy(v3d->blitter); 29701e04c3fSmrg 29801e04c3fSmrg if (v3d->uploader) 29901e04c3fSmrg u_upload_destroy(v3d->uploader); 3009f464c52Smaya if (v3d->state_uploader) 3019f464c52Smaya u_upload_destroy(v3d->state_uploader); 30201e04c3fSmrg 3037ec681f3Smrg if (v3d->prim_counts) 3047ec681f3Smrg pipe_resource_reference(&v3d->prim_counts, NULL); 3057ec681f3Smrg 30601e04c3fSmrg slab_destroy_child(&v3d->transfer_pool); 30701e04c3fSmrg 30801e04c3fSmrg pipe_surface_reference(&v3d->framebuffer.cbufs[0], NULL); 30901e04c3fSmrg pipe_surface_reference(&v3d->framebuffer.zsbuf, NULL); 31001e04c3fSmrg 3117ec681f3Smrg if (v3d->sand8_blit_vs) 3127ec681f3Smrg pctx->delete_vs_state(pctx, v3d->sand8_blit_vs); 3137ec681f3Smrg if (v3d->sand8_blit_fs_luma) 3147ec681f3Smrg pctx->delete_fs_state(pctx, v3d->sand8_blit_fs_luma); 3157ec681f3Smrg if (v3d->sand8_blit_fs_chroma) 3167ec681f3Smrg pctx->delete_fs_state(pctx, v3d->sand8_blit_fs_chroma); 3177ec681f3Smrg 31801e04c3fSmrg v3d_program_fini(pctx); 31901e04c3fSmrg 32001e04c3fSmrg ralloc_free(v3d); 32101e04c3fSmrg} 32201e04c3fSmrg 3239f464c52Smayastatic void 3249f464c52Smayav3d_get_sample_position(struct pipe_context *pctx, 3259f464c52Smaya unsigned sample_count, unsigned sample_index, 3269f464c52Smaya float *xy) 3279f464c52Smaya{ 3289f464c52Smaya struct v3d_context *v3d = v3d_context(pctx); 3299f464c52Smaya 3309f464c52Smaya if (sample_count <= 1) { 3319f464c52Smaya xy[0] = 0.5; 3329f464c52Smaya xy[1] = 0.5; 3339f464c52Smaya } else { 3349f464c52Smaya static const int xoffsets_v33[] = { 1, -3, 3, -1 }; 3359f464c52Smaya static const int xoffsets_v42[] = { -1, 3, -3, 1 }; 3369f464c52Smaya const int *xoffsets = (v3d->screen->devinfo.ver >= 42 ? 3379f464c52Smaya xoffsets_v42 : xoffsets_v33); 3389f464c52Smaya 3399f464c52Smaya xy[0] = 0.5 + xoffsets[sample_index] * .125; 3409f464c52Smaya xy[1] = .125 + sample_index * .25; 3419f464c52Smaya } 3429f464c52Smaya} 3439f464c52Smaya 34401e04c3fSmrgstruct pipe_context * 34501e04c3fSmrgv3d_context_create(struct pipe_screen *pscreen, void *priv, unsigned flags) 34601e04c3fSmrg{ 34701e04c3fSmrg struct v3d_screen *screen = v3d_screen(pscreen); 34801e04c3fSmrg struct v3d_context *v3d; 34901e04c3fSmrg 35001e04c3fSmrg /* Prevent dumping of the shaders built during context setup. */ 35101e04c3fSmrg uint32_t saved_shaderdb_flag = V3D_DEBUG & V3D_DEBUG_SHADERDB; 35201e04c3fSmrg V3D_DEBUG &= ~V3D_DEBUG_SHADERDB; 35301e04c3fSmrg 35401e04c3fSmrg v3d = rzalloc(NULL, struct v3d_context); 35501e04c3fSmrg if (!v3d) 35601e04c3fSmrg return NULL; 35701e04c3fSmrg struct pipe_context *pctx = &v3d->base; 35801e04c3fSmrg 35901e04c3fSmrg v3d->screen = screen; 36001e04c3fSmrg 36101e04c3fSmrg int ret = drmSyncobjCreate(screen->fd, DRM_SYNCOBJ_CREATE_SIGNALED, 36201e04c3fSmrg &v3d->out_sync); 36301e04c3fSmrg if (ret) { 36401e04c3fSmrg ralloc_free(v3d); 36501e04c3fSmrg return NULL; 36601e04c3fSmrg } 36701e04c3fSmrg 36801e04c3fSmrg pctx->screen = pscreen; 36901e04c3fSmrg pctx->priv = priv; 37001e04c3fSmrg pctx->destroy = v3d_context_destroy; 37101e04c3fSmrg pctx->flush = v3d_pipe_flush; 3729f464c52Smaya pctx->memory_barrier = v3d_memory_barrier; 3739f464c52Smaya pctx->set_debug_callback = v3d_set_debug_callback; 37401e04c3fSmrg pctx->invalidate_resource = v3d_invalidate_resource; 3759f464c52Smaya pctx->get_sample_position = v3d_get_sample_position; 37601e04c3fSmrg 37701e04c3fSmrg if (screen->devinfo.ver >= 41) { 37801e04c3fSmrg v3d41_draw_init(pctx); 37901e04c3fSmrg v3d41_state_init(pctx); 38001e04c3fSmrg } else { 38101e04c3fSmrg v3d33_draw_init(pctx); 38201e04c3fSmrg v3d33_state_init(pctx); 38301e04c3fSmrg } 38401e04c3fSmrg v3d_program_init(pctx); 38501e04c3fSmrg v3d_query_init(pctx); 38601e04c3fSmrg v3d_resource_context_init(pctx); 38701e04c3fSmrg 38801e04c3fSmrg v3d_job_init(v3d); 38901e04c3fSmrg 39001e04c3fSmrg v3d->fd = screen->fd; 39101e04c3fSmrg 39201e04c3fSmrg slab_create_child(&v3d->transfer_pool, &screen->transfer_pool); 39301e04c3fSmrg 39401e04c3fSmrg v3d->uploader = u_upload_create_default(&v3d->base); 39501e04c3fSmrg v3d->base.stream_uploader = v3d->uploader; 39601e04c3fSmrg v3d->base.const_uploader = v3d->uploader; 3979f464c52Smaya v3d->state_uploader = u_upload_create(&v3d->base, 3989f464c52Smaya 4096, 3999f464c52Smaya PIPE_BIND_CONSTANT_BUFFER, 4009f464c52Smaya PIPE_USAGE_STREAM, 0); 40101e04c3fSmrg 40201e04c3fSmrg v3d->blitter = util_blitter_create(pctx); 40301e04c3fSmrg if (!v3d->blitter) 40401e04c3fSmrg goto fail; 40501e04c3fSmrg v3d->blitter->use_index_buffer = true; 40601e04c3fSmrg 40701e04c3fSmrg V3D_DEBUG |= saved_shaderdb_flag; 40801e04c3fSmrg 4099f464c52Smaya v3d->sample_mask = (1 << V3D_MAX_SAMPLES) - 1; 41001e04c3fSmrg v3d->active_queries = true; 41101e04c3fSmrg 41201e04c3fSmrg return &v3d->base; 41301e04c3fSmrg 41401e04c3fSmrgfail: 41501e04c3fSmrg pctx->destroy(pctx); 41601e04c3fSmrg return NULL; 41701e04c3fSmrg} 418