Path: blob/21.2-virgl/src/gallium/drivers/nouveau/nv50/nv50_context.c
4574 views
/*1* Copyright 2010 Christoph Bumiller2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice shall be included in11* all copies or substantial portions of the Software.12*13* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR14* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,15* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL16* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR17* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,18* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR19* OTHER DEALINGS IN THE SOFTWARE.20*/2122#include "pipe/p_defines.h"23#include "util/u_framebuffer.h"24#include "util/u_upload_mgr.h"2526#include "nv50/nv50_context.h"27#include "nv50/nv50_screen.h"28#include "nv50/nv50_resource.h"2930static void31nv50_flush(struct pipe_context *pipe,32struct pipe_fence_handle **fence,33unsigned flags)34{35struct nouveau_screen *screen = nouveau_screen(pipe->screen);3637if (fence)38nouveau_fence_ref(screen->fence.current, (struct nouveau_fence **)fence);3940PUSH_KICK(screen->pushbuf);4142nouveau_context_update_frame_stats(nouveau_context(pipe));43}4445static void46nv50_texture_barrier(struct pipe_context *pipe, unsigned flags)47{48struct nouveau_pushbuf *push = nv50_context(pipe)->base.pushbuf;4950BEGIN_NV04(push, SUBC_3D(NV50_GRAPH_SERIALIZE), 1);51PUSH_DATA (push, 0);52BEGIN_NV04(push, NV50_3D(TEX_CACHE_CTL), 1);53PUSH_DATA (push, 0x20);54}5556static void57nv50_memory_barrier(struct pipe_context *pipe, unsigned flags)58{59struct nv50_context *nv50 = nv50_context(pipe);60struct nouveau_pushbuf *push = nv50->base.pushbuf;61int i, s;6263if (flags & PIPE_BARRIER_MAPPED_BUFFER) {64for (i = 0; i < nv50->num_vtxbufs; ++i) {65if (!nv50->vtxbuf[i].buffer.resource && !nv50->vtxbuf[i].is_user_buffer)66continue;67if (nv50->vtxbuf[i].buffer.resource->flags & PIPE_RESOURCE_FLAG_MAP_PERSISTENT)68nv50->base.vbo_dirty = true;69}7071for (s = 0; s < NV50_MAX_3D_SHADER_STAGES && !nv50->cb_dirty; ++s) {72uint32_t valid = nv50->constbuf_valid[s];7374while (valid && !nv50->cb_dirty) {75const unsigned i = ffs(valid) - 1;76struct pipe_resource *res;7778valid &= ~(1 << i);79if (nv50->constbuf[s][i].user)80continue;8182res = nv50->constbuf[s][i].u.buf;83if (!res)84continue;8586if (res->flags & PIPE_RESOURCE_FLAG_MAP_PERSISTENT)87nv50->cb_dirty = true;88}89}90} else {91BEGIN_NV04(push, SUBC_3D(NV50_GRAPH_SERIALIZE), 1);92PUSH_DATA (push, 0);93}9495/* If we're going to texture from a buffer/image written by a shader, we96* must flush the texture cache.97*/98if (flags & PIPE_BARRIER_TEXTURE) {99BEGIN_NV04(push, NV50_3D(TEX_CACHE_CTL), 1);100PUSH_DATA (push, 0x20);101}102103if (flags & PIPE_BARRIER_CONSTANT_BUFFER)104nv50->cb_dirty = true;105if (flags & (PIPE_BARRIER_VERTEX_BUFFER | PIPE_BARRIER_INDEX_BUFFER))106nv50->base.vbo_dirty = true;107}108109static void110nv50_emit_string_marker(struct pipe_context *pipe, const char *str, int len)111{112struct nouveau_pushbuf *push = nv50_context(pipe)->base.pushbuf;113int string_words = len / 4;114int data_words;115116if (len <= 0)117return;118string_words = MIN2(string_words, NV04_PFIFO_MAX_PACKET_LEN);119if (string_words == NV04_PFIFO_MAX_PACKET_LEN)120data_words = string_words;121else122data_words = string_words + !!(len & 3);123BEGIN_NI04(push, SUBC_3D(NV04_GRAPH_NOP), data_words);124if (string_words)125PUSH_DATAp(push, str, string_words);126if (string_words != data_words) {127int data = 0;128memcpy(&data, &str[string_words * 4], len & 3);129PUSH_DATA (push, data);130}131}132133void134nv50_default_kick_notify(struct nouveau_pushbuf *push)135{136struct nv50_screen *screen = push->user_priv;137138if (screen) {139nouveau_fence_next(&screen->base);140nouveau_fence_update(&screen->base, true);141if (screen->cur_ctx)142screen->cur_ctx->state.flushed = true;143}144}145146static void147nv50_context_unreference_resources(struct nv50_context *nv50)148{149unsigned s, i;150151nouveau_bufctx_del(&nv50->bufctx_3d);152nouveau_bufctx_del(&nv50->bufctx);153nouveau_bufctx_del(&nv50->bufctx_cp);154155util_unreference_framebuffer_state(&nv50->framebuffer);156157assert(nv50->num_vtxbufs <= PIPE_MAX_ATTRIBS);158for (i = 0; i < nv50->num_vtxbufs; ++i)159pipe_vertex_buffer_unreference(&nv50->vtxbuf[i]);160161for (s = 0; s < NV50_MAX_SHADER_STAGES; ++s) {162assert(nv50->num_textures[s] <= PIPE_MAX_SAMPLERS);163for (i = 0; i < nv50->num_textures[s]; ++i)164pipe_sampler_view_reference(&nv50->textures[s][i], NULL);165166for (i = 0; i < NV50_MAX_PIPE_CONSTBUFS; ++i)167if (!nv50->constbuf[s][i].user)168pipe_resource_reference(&nv50->constbuf[s][i].u.buf, NULL);169}170171for (i = 0; i < nv50->global_residents.size / sizeof(struct pipe_resource *);172++i) {173struct pipe_resource **res = util_dynarray_element(174&nv50->global_residents, struct pipe_resource *, i);175pipe_resource_reference(res, NULL);176}177util_dynarray_fini(&nv50->global_residents);178}179180static void181nv50_destroy(struct pipe_context *pipe)182{183struct nv50_context *nv50 = nv50_context(pipe);184185if (nv50->screen->cur_ctx == nv50) {186nv50->screen->cur_ctx = NULL;187/* Save off the state in case another context gets created */188nv50->screen->save_state = nv50->state;189}190191if (nv50->base.pipe.stream_uploader)192u_upload_destroy(nv50->base.pipe.stream_uploader);193194nouveau_pushbuf_bufctx(nv50->base.pushbuf, NULL);195nouveau_pushbuf_kick(nv50->base.pushbuf, nv50->base.pushbuf->channel);196197nv50_context_unreference_resources(nv50);198199FREE(nv50->blit);200201nouveau_context_destroy(&nv50->base);202}203204static int205nv50_invalidate_resource_storage(struct nouveau_context *ctx,206struct pipe_resource *res,207int ref)208{209struct nv50_context *nv50 = nv50_context(&ctx->pipe);210unsigned bind = res->bind ? res->bind : PIPE_BIND_VERTEX_BUFFER;211unsigned s, i;212213if (bind & PIPE_BIND_RENDER_TARGET) {214assert(nv50->framebuffer.nr_cbufs <= PIPE_MAX_COLOR_BUFS);215for (i = 0; i < nv50->framebuffer.nr_cbufs; ++i) {216if (nv50->framebuffer.cbufs[i] &&217nv50->framebuffer.cbufs[i]->texture == res) {218nv50->dirty_3d |= NV50_NEW_3D_FRAMEBUFFER;219nouveau_bufctx_reset(nv50->bufctx_3d, NV50_BIND_3D_FB);220if (!--ref)221return ref;222}223}224}225if (bind & PIPE_BIND_DEPTH_STENCIL) {226if (nv50->framebuffer.zsbuf &&227nv50->framebuffer.zsbuf->texture == res) {228nv50->dirty_3d |= NV50_NEW_3D_FRAMEBUFFER;229nouveau_bufctx_reset(nv50->bufctx_3d, NV50_BIND_3D_FB);230if (!--ref)231return ref;232}233}234235if (bind & (PIPE_BIND_VERTEX_BUFFER |236PIPE_BIND_INDEX_BUFFER |237PIPE_BIND_CONSTANT_BUFFER |238PIPE_BIND_STREAM_OUTPUT |239PIPE_BIND_SAMPLER_VIEW)) {240241assert(nv50->num_vtxbufs <= PIPE_MAX_ATTRIBS);242for (i = 0; i < nv50->num_vtxbufs; ++i) {243if (nv50->vtxbuf[i].buffer.resource == res) {244nv50->dirty_3d |= NV50_NEW_3D_ARRAYS;245nouveau_bufctx_reset(nv50->bufctx_3d, NV50_BIND_3D_VERTEX);246if (!--ref)247return ref;248}249}250251for (s = 0; s < NV50_MAX_SHADER_STAGES; ++s) {252assert(nv50->num_textures[s] <= PIPE_MAX_SAMPLERS);253for (i = 0; i < nv50->num_textures[s]; ++i) {254if (nv50->textures[s][i] &&255nv50->textures[s][i]->texture == res) {256if (unlikely(s == NV50_SHADER_STAGE_COMPUTE)) {257nv50->dirty_cp |= NV50_NEW_CP_TEXTURES;258nouveau_bufctx_reset(nv50->bufctx_cp, NV50_BIND_CP_TEXTURES);259} else {260nv50->dirty_3d |= NV50_NEW_3D_TEXTURES;261nouveau_bufctx_reset(nv50->bufctx_3d, NV50_BIND_3D_TEXTURES);262}263if (!--ref)264return ref;265}266}267}268269for (s = 0; s < NV50_MAX_SHADER_STAGES; ++s) {270for (i = 0; i < NV50_MAX_PIPE_CONSTBUFS; ++i) {271if (!(nv50->constbuf_valid[s] & (1 << i)))272continue;273if (!nv50->constbuf[s][i].user &&274nv50->constbuf[s][i].u.buf == res) {275nv50->constbuf_dirty[s] |= 1 << i;276if (unlikely(s == NV50_SHADER_STAGE_COMPUTE)) {277nv50->dirty_cp |= NV50_NEW_CP_CONSTBUF;278nouveau_bufctx_reset(nv50->bufctx_cp, NV50_BIND_CP_CB(i));279} else {280nv50->dirty_3d |= NV50_NEW_3D_CONSTBUF;281nouveau_bufctx_reset(nv50->bufctx_3d, NV50_BIND_3D_CB(s, i));282}283if (!--ref)284return ref;285}286}287}288}289290return ref;291}292293static void294nv50_context_get_sample_position(struct pipe_context *, unsigned, unsigned,295float *);296297struct pipe_context *298nv50_create(struct pipe_screen *pscreen, void *priv, unsigned ctxflags)299{300struct nv50_screen *screen = nv50_screen(pscreen);301struct nv50_context *nv50;302struct pipe_context *pipe;303int ret;304uint32_t flags;305306nv50 = CALLOC_STRUCT(nv50_context);307if (!nv50)308return NULL;309pipe = &nv50->base.pipe;310311if (!nv50_blitctx_create(nv50))312goto out_err;313314nv50->base.pushbuf = screen->base.pushbuf;315nv50->base.client = screen->base.client;316317ret = nouveau_bufctx_new(screen->base.client, 2, &nv50->bufctx);318if (!ret)319ret = nouveau_bufctx_new(screen->base.client, NV50_BIND_3D_COUNT,320&nv50->bufctx_3d);321if (!ret)322ret = nouveau_bufctx_new(screen->base.client, NV50_BIND_CP_COUNT,323&nv50->bufctx_cp);324if (ret)325goto out_err;326327nv50->base.screen = &screen->base;328nv50->base.copy_data = nv50_m2mf_copy_linear;329nv50->base.push_data = nv50_sifc_linear_u8;330nv50->base.push_cb = nv50_cb_push;331332nv50->screen = screen;333pipe->screen = pscreen;334pipe->priv = priv;335pipe->stream_uploader = u_upload_create_default(pipe);336if (!pipe->stream_uploader)337goto out_err;338pipe->const_uploader = pipe->stream_uploader;339340pipe->destroy = nv50_destroy;341342pipe->draw_vbo = nv50_draw_vbo;343pipe->clear = nv50_clear;344pipe->launch_grid = nv50_launch_grid;345346pipe->flush = nv50_flush;347pipe->texture_barrier = nv50_texture_barrier;348pipe->memory_barrier = nv50_memory_barrier;349pipe->get_sample_position = nv50_context_get_sample_position;350pipe->emit_string_marker = nv50_emit_string_marker;351352if (!screen->cur_ctx) {353/* Restore the last context's state here, normally handled during354* context switch355*/356nv50->state = screen->save_state;357screen->cur_ctx = nv50;358nouveau_pushbuf_bufctx(screen->base.pushbuf, nv50->bufctx);359}360nv50->base.pushbuf->kick_notify = nv50_default_kick_notify;361362nouveau_context_init(&nv50->base);363nv50_init_query_functions(nv50);364nv50_init_surface_functions(nv50);365nv50_init_state_functions(nv50);366nv50_init_resource_functions(pipe);367368nv50->base.invalidate_resource_storage = nv50_invalidate_resource_storage;369370if (screen->base.device->chipset < 0x84 ||371debug_get_bool_option("NOUVEAU_PMPEG", false)) {372/* PMPEG */373nouveau_context_init_vdec(&nv50->base);374} else if (screen->base.device->chipset < 0x98 ||375screen->base.device->chipset == 0xa0) {376/* VP2 */377pipe->create_video_codec = nv84_create_decoder;378pipe->create_video_buffer = nv84_video_buffer_create;379} else {380/* VP3/4 */381pipe->create_video_codec = nv98_create_decoder;382pipe->create_video_buffer = nv98_video_buffer_create;383}384385flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_RD;386387BCTX_REFN_bo(nv50->bufctx_3d, 3D_SCREEN, flags, screen->code);388BCTX_REFN_bo(nv50->bufctx_3d, 3D_SCREEN, flags, screen->uniforms);389BCTX_REFN_bo(nv50->bufctx_3d, 3D_SCREEN, flags, screen->txc);390BCTX_REFN_bo(nv50->bufctx_3d, 3D_SCREEN, flags, screen->stack_bo);391if (screen->compute) {392BCTX_REFN_bo(nv50->bufctx_cp, CP_SCREEN, flags, screen->code);393BCTX_REFN_bo(nv50->bufctx_cp, CP_SCREEN, flags, screen->uniforms);394BCTX_REFN_bo(nv50->bufctx_cp, CP_SCREEN, flags, screen->txc);395BCTX_REFN_bo(nv50->bufctx_cp, CP_SCREEN, flags, screen->stack_bo);396}397398flags = NOUVEAU_BO_GART | NOUVEAU_BO_WR;399400BCTX_REFN_bo(nv50->bufctx_3d, 3D_SCREEN, flags, screen->fence.bo);401BCTX_REFN_bo(nv50->bufctx, FENCE, flags, screen->fence.bo);402if (screen->compute)403BCTX_REFN_bo(nv50->bufctx_cp, CP_SCREEN, flags, screen->fence.bo);404405nv50->base.scratch.bo_size = 2 << 20;406407util_dynarray_init(&nv50->global_residents, NULL);408409// Make sure that the first TSC entry has SRGB conversion bit set, since we410// use it as a fallback.411if (!screen->tsc.entries[0])412nv50_upload_tsc0(nv50);413414// And mark samplers as dirty so that the first slot would get bound to the415// zero entry if it's not otherwise set.416nv50->dirty_3d |= NV50_NEW_3D_SAMPLERS;417418return pipe;419420out_err:421if (pipe->stream_uploader)422u_upload_destroy(pipe->stream_uploader);423if (nv50->bufctx_3d)424nouveau_bufctx_del(&nv50->bufctx_3d);425if (nv50->bufctx_cp)426nouveau_bufctx_del(&nv50->bufctx_cp);427if (nv50->bufctx)428nouveau_bufctx_del(&nv50->bufctx);429FREE(nv50->blit);430FREE(nv50);431return NULL;432}433434void435nv50_bufctx_fence(struct nouveau_bufctx *bufctx, bool on_flush)436{437struct nouveau_list *list = on_flush ? &bufctx->current : &bufctx->pending;438struct nouveau_list *it;439440for (it = list->next; it != list; it = it->next) {441struct nouveau_bufref *ref = (struct nouveau_bufref *)it;442struct nv04_resource *res = ref->priv;443if (res)444nv50_resource_validate(res, (unsigned)ref->priv_data);445}446}447448static void449nv50_context_get_sample_position(struct pipe_context *pipe,450unsigned sample_count, unsigned sample_index,451float *xy)452{453static const uint8_t ms1[1][2] = { { 0x8, 0x8 } };454static const uint8_t ms2[2][2] = {455{ 0x4, 0x4 }, { 0xc, 0xc } }; /* surface coords (0,0), (1,0) */456static const uint8_t ms4[4][2] = {457{ 0x6, 0x2 }, { 0xe, 0x6 }, /* (0,0), (1,0) */458{ 0x2, 0xa }, { 0xa, 0xe } }; /* (0,1), (1,1) */459static const uint8_t ms8[8][2] = {460{ 0x1, 0x7 }, { 0x5, 0x3 }, /* (0,0), (1,0) */461{ 0x3, 0xd }, { 0x7, 0xb }, /* (0,1), (1,1) */462{ 0x9, 0x5 }, { 0xf, 0x1 }, /* (2,0), (3,0) */463{ 0xb, 0xf }, { 0xd, 0x9 } }; /* (2,1), (3,1) */464#if 0465/* NOTE: there are alternative modes for MS2 and MS8, currently not used */466static const uint8_t ms8_alt[8][2] = {467{ 0x9, 0x5 }, { 0x7, 0xb }, /* (2,0), (1,1) */468{ 0xd, 0x9 }, { 0x5, 0x3 }, /* (3,1), (1,0) */469{ 0x3, 0xd }, { 0x1, 0x7 }, /* (0,1), (0,0) */470{ 0xb, 0xf }, { 0xf, 0x1 } }; /* (2,1), (3,0) */471#endif472473const uint8_t (*ptr)[2];474475switch (sample_count) {476case 0:477case 1: ptr = ms1; break;478case 2: ptr = ms2; break;479case 4: ptr = ms4; break;480case 8: ptr = ms8; break;481default:482assert(0);483return; /* bad sample count -> undefined locations */484}485xy[0] = ptr[sample_index][0] * 0.0625f;486xy[1] = ptr[sample_index][1] * 0.0625f;487}488489490