Path: blob/21.2-virgl/src/gallium/drivers/svga/svga_draw.c
4570 views
/**********************************************************1* Copyright 2008-2009 VMware, Inc. All rights reserved.2*3* Permission is hereby granted, free of charge, to any person4* obtaining a copy of this software and associated documentation5* files (the "Software"), to deal in the Software without6* restriction, including without limitation the rights to use, copy,7* modify, merge, publish, distribute, sublicense, and/or sell copies8* of the Software, and to permit persons to whom the Software is9* furnished to do so, subject to the following conditions:10*11* The above copyright notice and this permission notice shall be12* included in all copies or substantial portions of the Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,15* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF16* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND17* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS18* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN19* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN20* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE21* SOFTWARE.22*23**********************************************************/2425#include "pipe/p_compiler.h"26#include "util/u_inlines.h"27#include "pipe/p_defines.h"28#include "util/u_helpers.h"29#include "util/u_memory.h"30#include "util/u_math.h"3132#include "svga_context.h"33#include "svga_draw.h"34#include "svga_draw_private.h"35#include "svga_debug.h"36#include "svga_screen.h"37#include "svga_resource.h"38#include "svga_resource_buffer.h"39#include "svga_resource_texture.h"40#include "svga_sampler_view.h"41#include "svga_shader.h"42#include "svga_surface.h"43#include "svga_winsys.h"44#include "svga_cmd.h"454647struct svga_hwtnl *48svga_hwtnl_create(struct svga_context *svga)49{50struct svga_hwtnl *hwtnl = CALLOC_STRUCT(svga_hwtnl);51if (!hwtnl)52goto fail;5354hwtnl->svga = svga;5556hwtnl->cmd.swc = svga->swc;5758return hwtnl;5960fail:61return NULL;62}636465void66svga_hwtnl_destroy(struct svga_hwtnl *hwtnl)67{68unsigned i, j;6970for (i = 0; i < PIPE_PRIM_MAX; i++) {71for (j = 0; j < IDX_CACHE_MAX; j++) {72pipe_resource_reference(&hwtnl->index_cache[i][j].buffer, NULL);73}74}7576for (i = 0; i < hwtnl->cmd.vbuf_count; i++)77pipe_vertex_buffer_unreference(&hwtnl->cmd.vbufs[i]);7879for (i = 0; i < hwtnl->cmd.prim_count; i++)80pipe_resource_reference(&hwtnl->cmd.prim_ib[i], NULL);8182FREE(hwtnl);83}848586void87svga_hwtnl_set_flatshade(struct svga_hwtnl *hwtnl,88boolean flatshade, boolean flatshade_first)89{90struct svga_screen *svgascreen = svga_screen(hwtnl->svga->pipe.screen);9192/* User-specified PV */93hwtnl->api_pv = (flatshade && !flatshade_first) ? PV_LAST : PV_FIRST;9495/* Device supported PV */96if (svgascreen->haveProvokingVertex) {97/* use the mode specified by the user */98hwtnl->hw_pv = hwtnl->api_pv;99}100else {101/* the device only support first provoking vertex */102hwtnl->hw_pv = PV_FIRST;103}104}105106107void108svga_hwtnl_set_fillmode(struct svga_hwtnl *hwtnl, unsigned mode)109{110hwtnl->api_fillmode = mode;111}112113114void115svga_hwtnl_vertex_decls(struct svga_hwtnl *hwtnl,116unsigned count,117const SVGA3dVertexDecl * decls,118const unsigned *buffer_indexes,119SVGA3dElementLayoutId layout_id)120{121assert(hwtnl->cmd.prim_count == 0);122hwtnl->cmd.vdecl_count = count;123hwtnl->cmd.vdecl_layout_id = layout_id;124memcpy(hwtnl->cmd.vdecl, decls, count * sizeof(*decls));125memcpy(hwtnl->cmd.vdecl_buffer_index, buffer_indexes,126count * sizeof(unsigned));127}128129130/**131* Specify vertex buffers for hardware drawing.132*/133void134svga_hwtnl_vertex_buffers(struct svga_hwtnl *hwtnl,135unsigned count, struct pipe_vertex_buffer *buffers)136{137struct pipe_vertex_buffer *dst = hwtnl->cmd.vbufs;138const struct pipe_vertex_buffer *src = buffers;139unsigned i;140141for (i = 0; i < count; i++) {142pipe_vertex_buffer_reference(&dst[i], &src[i]);143}144145/* release old buffer references */146for ( ; i < hwtnl->cmd.vbuf_count; i++) {147pipe_vertex_buffer_unreference(&dst[i]);148/* don't bother zeroing stride/offset fields */149}150151hwtnl->cmd.vbuf_count = count;152}153154155/**156* Determine whether the specified buffer is referred in the primitive queue,157* for which no commands have been written yet.158*/159boolean160svga_hwtnl_is_buffer_referred(struct svga_hwtnl *hwtnl,161struct pipe_resource *buffer)162{163unsigned i;164165if (svga_buffer_is_user_buffer(buffer)) {166return FALSE;167}168169if (!hwtnl->cmd.prim_count) {170return FALSE;171}172173for (i = 0; i < hwtnl->cmd.vbuf_count; ++i) {174if (hwtnl->cmd.vbufs[i].buffer.resource == buffer) {175return TRUE;176}177}178179for (i = 0; i < hwtnl->cmd.prim_count; ++i) {180if (hwtnl->cmd.prim_ib[i] == buffer) {181return TRUE;182}183}184185return FALSE;186}187188189static enum pipe_error190draw_vgpu9(struct svga_hwtnl *hwtnl)191{192struct svga_winsys_context *swc = hwtnl->cmd.swc;193struct svga_context *svga = hwtnl->svga;194enum pipe_error ret;195struct svga_winsys_surface *vb_handle[SVGA3D_INPUTREG_MAX];196struct svga_winsys_surface *ib_handle[QSZ];197struct svga_winsys_surface *handle;198SVGA3dVertexDecl *vdecl;199SVGA3dPrimitiveRange *prim;200unsigned i;201202/* Re-validate those sampler views with backing copy203* of texture whose original copy has been updated.204* This is done here at draw time because the texture binding might not205* have modified, hence validation is not triggered at state update time,206* and yet the texture might have been updated in another context, so207* we need to re-validate the sampler view in order to update the backing208* copy of the updated texture.209*/210if (svga->state.hw_draw.num_backed_views) {211for (i = 0; i < svga->state.hw_draw.num_views; i++) {212struct svga_hw_view_state *view = &svga->state.hw_draw.views[i];213struct svga_texture *tex = svga_texture(view->texture);214struct svga_sampler_view *sv = view->v;215if (sv && tex && sv->handle != tex->handle && sv->age < tex->age)216svga_validate_sampler_view(svga, view->v);217}218}219220for (i = 0; i < hwtnl->cmd.vdecl_count; i++) {221unsigned j = hwtnl->cmd.vdecl_buffer_index[i];222handle = svga_buffer_handle(svga, hwtnl->cmd.vbufs[j].buffer.resource,223PIPE_BIND_VERTEX_BUFFER);224if (!handle)225return PIPE_ERROR_OUT_OF_MEMORY;226227vb_handle[i] = handle;228}229230for (i = 0; i < hwtnl->cmd.prim_count; i++) {231if (hwtnl->cmd.prim_ib[i]) {232handle = svga_buffer_handle(svga, hwtnl->cmd.prim_ib[i],233PIPE_BIND_INDEX_BUFFER);234if (!handle)235return PIPE_ERROR_OUT_OF_MEMORY;236}237else238handle = NULL;239240ib_handle[i] = handle;241}242243if (svga->rebind.flags.rendertargets) {244ret = svga_reemit_framebuffer_bindings(svga);245if (ret != PIPE_OK) {246return ret;247}248}249250if (svga->rebind.flags.texture_samplers) {251ret = svga_reemit_tss_bindings(svga);252if (ret != PIPE_OK) {253return ret;254}255}256257if (svga->rebind.flags.vs) {258ret = svga_reemit_vs_bindings(svga);259if (ret != PIPE_OK) {260return ret;261}262}263264if (svga->rebind.flags.fs) {265ret = svga_reemit_fs_bindings(svga);266if (ret != PIPE_OK) {267return ret;268}269}270271SVGA_DBG(DEBUG_DMA, "draw to sid %p, %d prims\n",272svga->curr.framebuffer.cbufs[0] ?273svga_surface(svga->curr.framebuffer.cbufs[0])->handle : NULL,274hwtnl->cmd.prim_count);275276ret = SVGA3D_BeginDrawPrimitives(swc,277&vdecl,278hwtnl->cmd.vdecl_count,279&prim, hwtnl->cmd.prim_count);280if (ret != PIPE_OK)281return ret;282283memcpy(vdecl,284hwtnl->cmd.vdecl,285hwtnl->cmd.vdecl_count * sizeof hwtnl->cmd.vdecl[0]);286287for (i = 0; i < hwtnl->cmd.vdecl_count; i++) {288/* check for 4-byte alignment */289assert(vdecl[i].array.offset % 4 == 0);290assert(vdecl[i].array.stride % 4 == 0);291292/* Given rangeHint is considered to be relative to indexBias, and293* indexBias varies per primitive, we cannot accurately supply an294* rangeHint when emitting more than one primitive per draw command.295*/296if (hwtnl->cmd.prim_count == 1) {297vdecl[i].rangeHint.first = hwtnl->cmd.min_index[0];298vdecl[i].rangeHint.last = hwtnl->cmd.max_index[0] + 1;299}300else {301vdecl[i].rangeHint.first = 0;302vdecl[i].rangeHint.last = 0;303}304305swc->surface_relocation(swc,306&vdecl[i].array.surfaceId,307NULL, vb_handle[i], SVGA_RELOC_READ);308}309310memcpy(prim,311hwtnl->cmd.prim, hwtnl->cmd.prim_count * sizeof hwtnl->cmd.prim[0]);312313for (i = 0; i < hwtnl->cmd.prim_count; i++) {314swc->surface_relocation(swc,315&prim[i].indexArray.surfaceId,316NULL, ib_handle[i], SVGA_RELOC_READ);317pipe_resource_reference(&hwtnl->cmd.prim_ib[i], NULL);318}319320SVGA_FIFOCommitAll(swc);321322hwtnl->cmd.prim_count = 0;323324return PIPE_OK;325}326327328static SVGA3dSurfaceFormat329xlate_index_format(unsigned indexWidth)330{331if (indexWidth == 2) {332return SVGA3D_R16_UINT;333}334else if (indexWidth == 4) {335return SVGA3D_R32_UINT;336}337else {338assert(!"Bad indexWidth");339return SVGA3D_R32_UINT;340}341}342343344static enum pipe_error345validate_sampler_resources(struct svga_context *svga)346{347enum pipe_shader_type shader;348349assert(svga_have_vgpu10(svga));350351for (shader = PIPE_SHADER_VERTEX; shader <= PIPE_SHADER_COMPUTE; shader++) {352unsigned count = svga->curr.num_sampler_views[shader];353unsigned i;354struct svga_winsys_surface *surfaces[PIPE_MAX_SAMPLERS];355enum pipe_error ret;356357/*358* Reference bound sampler resources to ensure pending updates are359* noticed by the device.360*/361for (i = 0; i < count; i++) {362struct svga_pipe_sampler_view *sv =363svga_pipe_sampler_view(svga->curr.sampler_views[shader][i]);364365if (sv) {366if (sv->base.texture->target == PIPE_BUFFER) {367surfaces[i] = svga_buffer_handle(svga, sv->base.texture,368PIPE_BIND_SAMPLER_VIEW);369}370else {371surfaces[i] = svga_texture(sv->base.texture)->handle;372}373}374else {375surfaces[i] = NULL;376}377}378379if (shader == PIPE_SHADER_FRAGMENT &&380svga->curr.rast->templ.poly_stipple_enable) {381const unsigned unit =382svga_fs_variant(svga->state.hw_draw.fs)->pstipple_sampler_unit;383struct svga_pipe_sampler_view *sv =384svga->polygon_stipple.sampler_view;385386assert(sv);387surfaces[unit] = svga_texture(sv->base.texture)->handle;388count = MAX2(count, unit+1);389}390391/* rebind the shader resources if needed */392if (svga->rebind.flags.texture_samplers) {393for (i = 0; i < count; i++) {394if (surfaces[i]) {395ret = svga->swc->resource_rebind(svga->swc,396surfaces[i],397NULL,398SVGA_RELOC_READ);399if (ret != PIPE_OK)400return ret;401}402}403}404}405svga->rebind.flags.texture_samplers = FALSE;406407return PIPE_OK;408}409410411static enum pipe_error412validate_constant_buffers(struct svga_context *svga)413{414enum pipe_shader_type shader;415416assert(svga_have_vgpu10(svga));417418for (shader = PIPE_SHADER_VERTEX; shader <= PIPE_SHADER_COMPUTE; shader++) {419enum pipe_error ret;420struct svga_buffer *buffer;421422/* Rebind the default constant buffer if needed */423if (svga->rebind.flags.constbufs) {424buffer = svga_buffer(svga->state.hw_draw.constbuf[shader][0]);425if (buffer) {426ret = svga->swc->resource_rebind(svga->swc,427buffer->handle,428NULL,429SVGA_RELOC_READ);430if (ret != PIPE_OK)431return ret;432}433}434435struct svga_winsys_surface *handle;436unsigned enabled_constbufs;437438/*439* Reference other bound constant buffers to ensure pending updates are440* noticed by the device.441*/442enabled_constbufs = svga->state.hw_draw.enabled_constbufs[shader] & ~1u;443while (enabled_constbufs) {444unsigned i = u_bit_scan(&enabled_constbufs);445buffer = svga_buffer(svga->curr.constbufs[shader][i].buffer);446447/* If the constant buffer has hw storage, get the buffer winsys handle.448* Rebind the resource if needed.449*/450if (buffer && !buffer->use_swbuf)451handle = svga_buffer_handle(svga, &buffer->b,452PIPE_BIND_CONSTANT_BUFFER);453else454handle = svga->state.hw_draw.constbufoffsets[shader][i].handle;455456if (svga->rebind.flags.constbufs && handle) {457ret = svga->swc->resource_rebind(svga->swc,458handle,459NULL,460SVGA_RELOC_READ);461if (ret != PIPE_OK)462return ret;463}464}465}466svga->rebind.flags.constbufs = FALSE;467468return PIPE_OK;469}470471472/**473* Was the last command put into the command buffer a drawing command?474* We use this to determine if we can skip emitting buffer re-bind475* commands when we have a sequence of drawing commands that use the476* same vertex/index buffers with no intervening commands.477*478* The first drawing command will bind the vertex/index buffers. If479* the immediately following command is also a drawing command using the480* same buffers, we shouldn't have to rebind them.481*/482static bool483last_command_was_draw(const struct svga_context *svga)484{485switch (SVGA3D_GetLastCommand(svga->swc)) {486case SVGA_3D_CMD_DX_DRAW:487case SVGA_3D_CMD_DX_DRAW_INDEXED:488case SVGA_3D_CMD_DX_DRAW_INSTANCED:489case SVGA_3D_CMD_DX_DRAW_INDEXED_INSTANCED:490case SVGA_3D_CMD_DX_DRAW_AUTO:491case SVGA_3D_CMD_DX_DRAW_INDEXED_INSTANCED_INDIRECT:492case SVGA_3D_CMD_DX_DRAW_INSTANCED_INDIRECT:493return true;494default:495return false;496}497}498499500/**501* A helper function to compare vertex buffers.502* They are equal if the vertex buffer attributes and the vertex buffer503* resources are identical.504*/505static boolean506vertex_buffers_equal(unsigned count,507SVGA3dVertexBuffer *pVBufAttr1,508struct pipe_resource **pVBuf1,509SVGA3dVertexBuffer *pVBufAttr2,510struct pipe_resource **pVBuf2)511{512return (memcmp(pVBufAttr1, pVBufAttr2,513count * sizeof(*pVBufAttr1)) == 0) &&514(memcmp(pVBuf1, pVBuf2, count * sizeof(*pVBuf1)) == 0);515}516517518/*519* Prepare the vertex buffers for a drawing command.520*/521static enum pipe_error522validate_vertex_buffers(struct svga_hwtnl *hwtnl,523const struct pipe_stream_output_target *so_vertex_count)524{525struct svga_context *svga = hwtnl->svga;526struct pipe_resource *vbuffers[SVGA3D_INPUTREG_MAX];527struct svga_winsys_surface *vbuffer_handles[SVGA3D_INPUTREG_MAX];528struct svga_winsys_surface *so_vertex_count_handle;529const unsigned vbuf_count = so_vertex_count ? 1 : hwtnl->cmd.vbuf_count;530int last_vbuf = -1;531unsigned i;532533assert(svga_have_vgpu10(svga));534535/* Get handle for each referenced vertex buffer, unless we're using a536* stream-out buffer to specify the drawing information (DrawAuto).537*/538if (so_vertex_count) {539i = 0;540}541else {542for (i = 0; i < vbuf_count; i++) {543struct svga_buffer *sbuf =544svga_buffer(hwtnl->cmd.vbufs[i].buffer.resource);545546if (sbuf) {547vbuffer_handles[i] = svga_buffer_handle(svga, &sbuf->b,548PIPE_BIND_VERTEX_BUFFER);549assert(sbuf->key.flags & SVGA3D_SURFACE_BIND_VERTEX_BUFFER);550if (vbuffer_handles[i] == NULL)551return PIPE_ERROR_OUT_OF_MEMORY;552vbuffers[i] = &sbuf->b;553last_vbuf = i;554}555else {556vbuffers[i] = NULL;557vbuffer_handles[i] = NULL;558}559}560}561562for (; i < svga->state.hw_draw.num_vbuffers; i++) {563vbuffers[i] = NULL;564vbuffer_handles[i] = NULL;565}566567/* Get handle for each referenced vertex buffer */568for (i = 0; i < vbuf_count; i++) {569struct svga_buffer *sbuf =570svga_buffer(hwtnl->cmd.vbufs[i].buffer.resource);571572if (sbuf) {573vbuffer_handles[i] = svga_buffer_handle(svga, &sbuf->b,574PIPE_BIND_VERTEX_BUFFER);575assert(sbuf->key.flags & SVGA3D_SURFACE_BIND_VERTEX_BUFFER);576if (vbuffer_handles[i] == NULL)577return PIPE_ERROR_OUT_OF_MEMORY;578vbuffers[i] = &sbuf->b;579last_vbuf = i;580}581else {582vbuffers[i] = NULL;583vbuffer_handles[i] = NULL;584}585}586587for (; i < svga->state.hw_draw.num_vbuffers; i++) {588vbuffers[i] = NULL;589vbuffer_handles[i] = NULL;590}591592/* setup vertex attribute input layout */593if (svga->state.hw_draw.layout_id != hwtnl->cmd.vdecl_layout_id) {594enum pipe_error ret =595SVGA3D_vgpu10_SetInputLayout(svga->swc,596hwtnl->cmd.vdecl_layout_id);597if (ret != PIPE_OK)598return ret;599600svga->state.hw_draw.layout_id = hwtnl->cmd.vdecl_layout_id;601}602603/* Get handle for the stream out buffer */604if (so_vertex_count) {605so_vertex_count_handle = svga_buffer_handle(svga,606so_vertex_count->buffer,607(PIPE_BIND_VERTEX_BUFFER |608PIPE_BIND_STREAM_OUTPUT));609if (!so_vertex_count_handle)610return PIPE_ERROR_OUT_OF_MEMORY;611}612else {613so_vertex_count_handle = NULL;614}615616/* setup vertex buffers */617{618SVGA3dVertexBuffer vbuffer_attrs[PIPE_MAX_ATTRIBS];619620if (so_vertex_count) {621/* Set IA slot0 input buffer to the SO buffer */622assert(vbuf_count == 1);623vbuffer_attrs[0].stride = hwtnl->cmd.vbufs[0].stride;624vbuffer_attrs[0].offset = hwtnl->cmd.vbufs[0].buffer_offset;625vbuffer_attrs[0].sid = 0;626vbuffers[0] = so_vertex_count->buffer;627vbuffer_handles[0] = so_vertex_count_handle;628}629else {630for (i = 0; i < vbuf_count; i++) {631vbuffer_attrs[i].stride = hwtnl->cmd.vbufs[i].stride;632vbuffer_attrs[i].offset = hwtnl->cmd.vbufs[i].buffer_offset;633vbuffer_attrs[i].sid = 0;634}635}636637/* If any of the vertex buffer state has changed, issue638* the SetVertexBuffers command. Otherwise, we will just639* need to rebind the resources.640*/641if (vbuf_count != svga->state.hw_draw.num_vbuffers ||642!vertex_buffers_equal(vbuf_count,643vbuffer_attrs,644vbuffers,645svga->state.hw_draw.vbuffer_attrs,646svga->state.hw_draw.vbuffers)) {647648unsigned num_vbuffers;649650/* get the max of the current bound vertex buffers count and651* the to-be-bound vertex buffers count, so as to unbind652* the unused vertex buffers.653*/654num_vbuffers = MAX2(vbuf_count, svga->state.hw_draw.num_vbuffers);655656/* Zero-out the old buffers we want to unbind (the number of loop657* iterations here is typically very small, and often zero.)658*/659for (i = vbuf_count; i < num_vbuffers; i++) {660vbuffer_attrs[i].sid = 0;661vbuffer_attrs[i].stride = 0;662vbuffer_attrs[i].offset = 0;663vbuffer_handles[i] = NULL;664}665666if (num_vbuffers > 0) {667SVGA3dVertexBuffer *pbufAttrs = vbuffer_attrs;668struct svga_winsys_surface **pbufHandles = vbuffer_handles;669unsigned numVBuf = 0;670671/* Loop through the vertex buffer lists to only emit672* those vertex buffers that are not already in the673* corresponding entries in the device's vertex buffer list.674*/675for (i = 0; i < num_vbuffers; i++) {676boolean emit =677vertex_buffers_equal(1,678&vbuffer_attrs[i],679&vbuffers[i],680&svga->state.hw_draw.vbuffer_attrs[i],681&svga->state.hw_draw.vbuffers[i]);682683if (!emit && i == num_vbuffers-1) {684/* Include the last vertex buffer in the next emit685* if it is different.686*/687emit = TRUE;688numVBuf++;689i++;690}691692if (emit) {693/* numVBuf can only be 0 if the first vertex buffer694* is the same as the one in the device's list.695* In this case, there is nothing to send yet.696*/697if (numVBuf) {698enum pipe_error ret =699SVGA3D_vgpu10_SetVertexBuffers(svga->swc,700numVBuf,701i - numVBuf,702pbufAttrs, pbufHandles);703if (ret != PIPE_OK)704return ret;705}706pbufAttrs += (numVBuf + 1);707pbufHandles += (numVBuf + 1);708numVBuf = 0;709}710else711numVBuf++;712}713714/* save the number of vertex buffers sent to the device, not715* including trailing unbound vertex buffers.716*/717svga->state.hw_draw.num_vbuffers = last_vbuf + 1;718memcpy(svga->state.hw_draw.vbuffer_attrs, vbuffer_attrs,719num_vbuffers * sizeof(vbuffer_attrs[0]));720for (i = 0; i < num_vbuffers; i++) {721pipe_resource_reference(&svga->state.hw_draw.vbuffers[i],722vbuffers[i]);723}724}725}726else {727/* Even though we can avoid emitting the redundant SetVertexBuffers728* command, we still need to reference the vertex buffers surfaces.729*/730for (i = 0; i < vbuf_count; i++) {731if (vbuffer_handles[i] && !last_command_was_draw(svga)) {732enum pipe_error ret =733svga->swc->resource_rebind(svga->swc, vbuffer_handles[i],734NULL, SVGA_RELOC_READ);735if (ret != PIPE_OK)736return ret;737}738}739}740}741742return PIPE_OK;743}744745746/*747* Prepare the index buffer for a drawing command.748*/749static enum pipe_error750validate_index_buffer(struct svga_hwtnl *hwtnl,751const SVGA3dPrimitiveRange *range,752struct pipe_resource *ib)753{754struct svga_context *svga = hwtnl->svga;755struct svga_winsys_surface *ib_handle =756svga_buffer_handle(svga, ib, PIPE_BIND_INDEX_BUFFER);757758if (!ib_handle)759return PIPE_ERROR_OUT_OF_MEMORY;760761struct svga_buffer *sbuf = svga_buffer(ib);762assert(sbuf->key.flags & SVGA3D_SURFACE_BIND_INDEX_BUFFER);763(void) sbuf; /* silence unused var warning */764765SVGA3dSurfaceFormat indexFormat = xlate_index_format(range->indexWidth);766767if (ib != svga->state.hw_draw.ib ||768indexFormat != svga->state.hw_draw.ib_format ||769range->indexArray.offset != svga->state.hw_draw.ib_offset) {770771assert(indexFormat != SVGA3D_FORMAT_INVALID);772enum pipe_error ret =773SVGA3D_vgpu10_SetIndexBuffer(svga->swc, ib_handle,774indexFormat,775range->indexArray.offset);776if (ret != PIPE_OK)777return ret;778779pipe_resource_reference(&svga->state.hw_draw.ib, ib);780svga->state.hw_draw.ib_format = indexFormat;781svga->state.hw_draw.ib_offset = range->indexArray.offset;782}783else {784/* Even though we can avoid emitting the redundant SetIndexBuffer785* command, we still need to reference the index buffer surface.786*/787if (!last_command_was_draw(svga)) {788enum pipe_error ret = svga->swc->resource_rebind(svga->swc,789ib_handle,790NULL,791SVGA_RELOC_READ);792if (ret != PIPE_OK)793return ret;794}795}796797return PIPE_OK;798}799800801static enum pipe_error802draw_vgpu10(struct svga_hwtnl *hwtnl,803const SVGA3dPrimitiveRange *range,804unsigned vcount,805unsigned min_index, unsigned max_index,806struct pipe_resource *ib,807unsigned start_instance, unsigned instance_count,808const struct pipe_draw_indirect_info *indirect,809const struct pipe_stream_output_target *so_vertex_count)810{811struct svga_context *svga = hwtnl->svga;812struct svga_winsys_surface *indirect_handle;813enum pipe_error ret;814815assert(svga_have_vgpu10(svga));816assert(hwtnl->cmd.prim_count == 0);817818/* We need to reemit all the current resource bindings along with the Draw819* command to be sure that the referenced resources are available for the820* Draw command, just in case the surfaces associated with the resources821* are paged out.822*/823if (svga->rebind.val) {824ret = svga_rebind_framebuffer_bindings(svga);825if (ret != PIPE_OK)826return ret;827828ret = svga_rebind_shaders(svga);829if (ret != PIPE_OK)830return ret;831832/* Rebind stream output targets */833ret = svga_rebind_stream_output_targets(svga);834if (ret != PIPE_OK)835return ret;836837/* No need to explicitly rebind index buffer and vertex buffers here.838* Even if the same index buffer or vertex buffers are referenced for this839* draw and we skip emitting the redundant set command, we will still840* reference the associated resources.841*/842}843844ret = validate_sampler_resources(svga);845if (ret != PIPE_OK)846return ret;847848ret = validate_constant_buffers(svga);849if (ret != PIPE_OK)850return ret;851852ret = validate_vertex_buffers(hwtnl, so_vertex_count);853if (ret != PIPE_OK)854return ret;855856if (ib) {857ret = validate_index_buffer(hwtnl, range, ib);858if (ret != PIPE_OK)859return ret;860}861862if (indirect) {863indirect_handle = svga_buffer_handle(svga, indirect->buffer,864PIPE_BIND_COMMAND_ARGS_BUFFER);865if (!indirect_handle)866return PIPE_ERROR_OUT_OF_MEMORY;867}868else {869indirect_handle = NULL;870}871872/* Set primitive type (line, tri, etc) */873if (svga->state.hw_draw.topology != range->primType) {874ret = SVGA3D_vgpu10_SetTopology(svga->swc, range->primType);875if (ret != PIPE_OK)876return ret;877878svga->state.hw_draw.topology = range->primType;879}880881if (ib) {882/* indexed drawing */883if (indirect) {884ret = SVGA3D_sm5_DrawIndexedInstancedIndirect(svga->swc,885indirect_handle,886indirect->offset);887}888else if (instance_count > 1) {889ret = SVGA3D_vgpu10_DrawIndexedInstanced(svga->swc,890vcount,891instance_count,8920, /* startIndexLocation */893range->indexBias,894start_instance);895}896else {897/* non-instanced drawing */898ret = SVGA3D_vgpu10_DrawIndexed(svga->swc,899vcount,9000, /* startIndexLocation */901range->indexBias);902}903if (ret != PIPE_OK) {904return ret;905}906}907else {908/* non-indexed drawing */909if (svga->state.hw_draw.ib_format != SVGA3D_FORMAT_INVALID ||910svga->state.hw_draw.ib != NULL) {911/* Unbind previously bound index buffer */912ret = SVGA3D_vgpu10_SetIndexBuffer(svga->swc, NULL,913SVGA3D_FORMAT_INVALID, 0);914if (ret != PIPE_OK)915return ret;916pipe_resource_reference(&svga->state.hw_draw.ib, NULL);917svga->state.hw_draw.ib_format = SVGA3D_FORMAT_INVALID;918}919920assert(svga->state.hw_draw.ib == NULL);921922if (so_vertex_count) {923/* Stream-output drawing */924ret = SVGA3D_vgpu10_DrawAuto(svga->swc);925}926else if (indirect) {927ret = SVGA3D_sm5_DrawInstancedIndirect(svga->swc,928indirect_handle,929indirect->offset);930}931else if (instance_count > 1) {932ret = SVGA3D_vgpu10_DrawInstanced(svga->swc,933vcount,934instance_count,935range->indexBias,936start_instance);937}938else {939/* non-instanced */940ret = SVGA3D_vgpu10_Draw(svga->swc,941vcount,942range->indexBias);943}944if (ret != PIPE_OK) {945return ret;946}947}948949hwtnl->cmd.prim_count = 0;950951return PIPE_OK;952}953954955956/**957* Emit any pending drawing commands to the command buffer.958* When we receive VGPU9 drawing commands we accumulate them and don't959* immediately emit them into the command buffer.960* This function needs to be called before we change state that could961* effect those pending draws.962*/963enum pipe_error964svga_hwtnl_flush(struct svga_hwtnl *hwtnl)965{966enum pipe_error ret = PIPE_OK;967968SVGA_STATS_TIME_PUSH(svga_sws(hwtnl->svga), SVGA_STATS_TIME_HWTNLFLUSH);969970if (!svga_have_vgpu10(hwtnl->svga) && hwtnl->cmd.prim_count) {971/* we only queue up primitive for VGPU9 */972ret = draw_vgpu9(hwtnl);973}974975SVGA_STATS_TIME_POP(svga_screen(hwtnl->svga->pipe.screen)->sws);976return ret;977}978979980void981svga_hwtnl_set_index_bias(struct svga_hwtnl *hwtnl, int index_bias)982{983hwtnl->index_bias = index_bias;984}985986987988/***********************************************************************989* Internal functions:990*/991992/**993* For debugging only.994*/995static void996check_draw_params(struct svga_hwtnl *hwtnl,997const SVGA3dPrimitiveRange *range,998unsigned min_index, unsigned max_index,999struct pipe_resource *ib)1000{1001unsigned i;10021003assert(!svga_have_vgpu10(hwtnl->svga));10041005for (i = 0; i < hwtnl->cmd.vdecl_count; i++) {1006unsigned j = hwtnl->cmd.vdecl_buffer_index[i];1007const struct pipe_vertex_buffer *vb = &hwtnl->cmd.vbufs[j];1008unsigned size = vb->buffer.resource ? vb->buffer.resource->width0 : 0;1009unsigned offset = hwtnl->cmd.vdecl[i].array.offset;1010unsigned stride = hwtnl->cmd.vdecl[i].array.stride;1011int index_bias = (int) range->indexBias + hwtnl->index_bias;1012unsigned width;10131014if (size == 0)1015continue;10161017assert(vb);1018assert(size);1019assert(offset < size);1020assert(min_index <= max_index);1021(void) width;1022(void) stride;1023(void) offset;1024(void) size;10251026switch (hwtnl->cmd.vdecl[i].identity.type) {1027case SVGA3D_DECLTYPE_FLOAT1:1028width = 4;1029break;1030case SVGA3D_DECLTYPE_FLOAT2:1031width = 4 * 2;1032break;1033case SVGA3D_DECLTYPE_FLOAT3:1034width = 4 * 3;1035break;1036case SVGA3D_DECLTYPE_FLOAT4:1037width = 4 * 4;1038break;1039case SVGA3D_DECLTYPE_D3DCOLOR:1040width = 4;1041break;1042case SVGA3D_DECLTYPE_UBYTE4:1043width = 1 * 4;1044break;1045case SVGA3D_DECLTYPE_SHORT2:1046width = 2 * 2;1047break;1048case SVGA3D_DECLTYPE_SHORT4:1049width = 2 * 4;1050break;1051case SVGA3D_DECLTYPE_UBYTE4N:1052width = 1 * 4;1053break;1054case SVGA3D_DECLTYPE_SHORT2N:1055width = 2 * 2;1056break;1057case SVGA3D_DECLTYPE_SHORT4N:1058width = 2 * 4;1059break;1060case SVGA3D_DECLTYPE_USHORT2N:1061width = 2 * 2;1062break;1063case SVGA3D_DECLTYPE_USHORT4N:1064width = 2 * 4;1065break;1066case SVGA3D_DECLTYPE_UDEC3:1067width = 4;1068break;1069case SVGA3D_DECLTYPE_DEC3N:1070width = 4;1071break;1072case SVGA3D_DECLTYPE_FLOAT16_2:1073width = 2 * 2;1074break;1075case SVGA3D_DECLTYPE_FLOAT16_4:1076width = 2 * 4;1077break;1078default:1079assert(0);1080width = 0;1081break;1082}10831084if (index_bias >= 0) {1085assert(offset + index_bias * stride + width <= size);1086}10871088/*1089* min_index/max_index are merely conservative guesses, so we can't1090* make buffer overflow detection based on their values.1091*/1092}10931094assert(range->indexWidth == range->indexArray.stride);10951096if (ib) {1097ASSERTED unsigned size = ib->width0;1098ASSERTED unsigned offset = range->indexArray.offset;1099ASSERTED unsigned stride = range->indexArray.stride;1100ASSERTED unsigned count;11011102assert(size);1103assert(offset < size);1104assert(stride);11051106switch (range->primType) {1107case SVGA3D_PRIMITIVE_POINTLIST:1108count = range->primitiveCount;1109break;1110case SVGA3D_PRIMITIVE_LINELIST:1111count = range->primitiveCount * 2;1112break;1113case SVGA3D_PRIMITIVE_LINESTRIP:1114count = range->primitiveCount + 1;1115break;1116case SVGA3D_PRIMITIVE_TRIANGLELIST:1117count = range->primitiveCount * 3;1118break;1119case SVGA3D_PRIMITIVE_TRIANGLESTRIP:1120count = range->primitiveCount + 2;1121break;1122case SVGA3D_PRIMITIVE_TRIANGLEFAN:1123count = range->primitiveCount + 2;1124break;1125default:1126assert(0);1127count = 0;1128break;1129}11301131assert(offset + count * stride <= size);1132}1133}113411351136/**1137* All drawing filters down into this function, either directly1138* on the hardware path or after doing software vertex processing.1139* \param indirect if non-null, get the vertex count, first vertex, etc.1140* from a buffer.1141* \param so_vertex_count if non-null, get the vertex count from a1142* stream-output target.1143*/1144enum pipe_error1145svga_hwtnl_prim(struct svga_hwtnl *hwtnl,1146const SVGA3dPrimitiveRange *range,1147unsigned vcount,1148unsigned min_index, unsigned max_index,1149struct pipe_resource *ib,1150unsigned start_instance, unsigned instance_count,1151const struct pipe_draw_indirect_info *indirect,1152const struct pipe_stream_output_target *so_vertex_count)1153{1154enum pipe_error ret = PIPE_OK;11551156SVGA_STATS_TIME_PUSH(svga_sws(hwtnl->svga), SVGA_STATS_TIME_HWTNLPRIM);11571158if (svga_have_vgpu10(hwtnl->svga)) {1159/* draw immediately */1160SVGA_RETRY(hwtnl->svga, draw_vgpu10(hwtnl, range, vcount, min_index,1161max_index, ib, start_instance,1162instance_count, indirect,1163so_vertex_count));1164}1165else {1166/* batch up drawing commands */1167assert(indirect == NULL);1168#ifdef DEBUG1169check_draw_params(hwtnl, range, min_index, max_index, ib);1170assert(start_instance == 0);1171assert(instance_count <= 1);1172#else1173(void) check_draw_params;1174#endif11751176if (hwtnl->cmd.prim_count + 1 >= QSZ) {1177ret = svga_hwtnl_flush(hwtnl);1178if (ret != PIPE_OK)1179goto done;1180}11811182/* min/max indices are relative to bias */1183hwtnl->cmd.min_index[hwtnl->cmd.prim_count] = min_index;1184hwtnl->cmd.max_index[hwtnl->cmd.prim_count] = max_index;11851186hwtnl->cmd.prim[hwtnl->cmd.prim_count] = *range;1187hwtnl->cmd.prim[hwtnl->cmd.prim_count].indexBias += hwtnl->index_bias;11881189pipe_resource_reference(&hwtnl->cmd.prim_ib[hwtnl->cmd.prim_count], ib);1190hwtnl->cmd.prim_count++;1191}11921193done:1194SVGA_STATS_TIME_POP(svga_screen(hwtnl->svga->pipe.screen)->sws);1195return ret;1196}119711981199/**1200* Return TRUE if there are pending primitives.1201*/1202boolean1203svga_hwtnl_has_pending_prim(struct svga_hwtnl *hwtnl)1204{1205return hwtnl->cmd.prim_count > 0;1206}120712081209