101e04c3fSmrg/**************************************************************************** 201e04c3fSmrg * Copyright (C) 2015 Intel Corporation. All Rights Reserved. 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 "swr_screen.h" 2501e04c3fSmrg#include "swr_context.h" 2601e04c3fSmrg#include "swr_resource.h" 2701e04c3fSmrg#include "swr_fence.h" 2801e04c3fSmrg#include "swr_query.h" 2901e04c3fSmrg#include "jit_api.h" 3001e04c3fSmrg 3101e04c3fSmrg#include "util/u_draw.h" 3201e04c3fSmrg#include "util/u_prim.h" 3301e04c3fSmrg 347ec681f3Smrg#include <algorithm> 357ec681f3Smrg#include <iostream> 3601e04c3fSmrg/* 3701e04c3fSmrg * Draw vertex arrays, with optional indexing, optional instancing. 3801e04c3fSmrg */ 3901e04c3fSmrgstatic void 407ec681f3Smrgswr_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info, 417ec681f3Smrg unsigned drawid_offset, 427ec681f3Smrg const struct pipe_draw_indirect_info *indirect, 437ec681f3Smrg const struct pipe_draw_start_count_bias *draws, 447ec681f3Smrg unsigned num_draws) 4501e04c3fSmrg{ 467ec681f3Smrg if (num_draws > 1) { 477ec681f3Smrg struct pipe_draw_info tmp_info = *info; 487ec681f3Smrg unsigned drawid = drawid_offset; 497ec681f3Smrg 507ec681f3Smrg for (unsigned i = 0; i < num_draws; i++) { 517ec681f3Smrg swr_draw_vbo(pipe, &tmp_info, drawid, indirect, &draws[i], 1); 527ec681f3Smrg if (tmp_info.increment_draw_id) 537ec681f3Smrg drawid++; 547ec681f3Smrg } 557ec681f3Smrg return; 567ec681f3Smrg } 577ec681f3Smrg 587ec681f3Smrg if (!indirect && (!draws[0].count || !info->instance_count)) 597ec681f3Smrg return; 607ec681f3Smrg 6101e04c3fSmrg struct swr_context *ctx = swr_context(pipe); 6201e04c3fSmrg 637ec681f3Smrg if (!indirect && 6401e04c3fSmrg !info->primitive_restart && 657ec681f3Smrg !u_trim_pipe_prim((enum pipe_prim_type)info->mode, (unsigned*)&draws[0].count)) 6601e04c3fSmrg return; 6701e04c3fSmrg 6801e04c3fSmrg if (!swr_check_render_cond(pipe)) 6901e04c3fSmrg return; 7001e04c3fSmrg 717ec681f3Smrg if (indirect && indirect->buffer) { 727ec681f3Smrg util_draw_indirect(pipe, info, indirect); 7301e04c3fSmrg return; 7401e04c3fSmrg } 7501e04c3fSmrg 7601e04c3fSmrg /* If indexed draw, force vertex validation since index buffer comes 7701e04c3fSmrg * from draw info. */ 7801e04c3fSmrg if (info->index_size) 7901e04c3fSmrg ctx->dirty |= SWR_NEW_VERTEX; 8001e04c3fSmrg 8101e04c3fSmrg /* Update derived state, pass draw info to update function. */ 827ec681f3Smrg swr_update_derived(pipe, info, draws); 8301e04c3fSmrg 8401e04c3fSmrg swr_update_draw_context(ctx); 8501e04c3fSmrg 867ec681f3Smrg struct pipe_draw_info resolved_info; 877ec681f3Smrg struct pipe_draw_start_count_bias resolved_draw; 887ec681f3Smrg /* DrawTransformFeedback */ 897ec681f3Smrg if (indirect && indirect->count_from_stream_output) { 907ec681f3Smrg // trick copied from softpipe to modify const struct *info 917ec681f3Smrg memcpy(&resolved_info, (void*)info, sizeof(struct pipe_draw_info)); 927ec681f3Smrg resolved_draw.start = draws[0].start; 937ec681f3Smrg resolved_draw.count = ctx->so_primCounter * ctx->patch_vertices; 947ec681f3Smrg resolved_info.max_index = resolved_draw.count - 1; 957ec681f3Smrg info = &resolved_info; 967ec681f3Smrg indirect = NULL; 977ec681f3Smrg draws = &resolved_draw; 987ec681f3Smrg } 997ec681f3Smrg 10001e04c3fSmrg if (ctx->vs->pipe.stream_output.num_outputs) { 10101e04c3fSmrg if (!ctx->vs->soFunc[info->mode]) { 10201e04c3fSmrg STREAMOUT_COMPILE_STATE state = {0}; 10301e04c3fSmrg struct pipe_stream_output_info *so = &ctx->vs->pipe.stream_output; 10401e04c3fSmrg 1057ec681f3Smrg state.numVertsPerPrim = u_vertices_per_prim((enum pipe_prim_type)info->mode); 10601e04c3fSmrg 10701e04c3fSmrg uint32_t offsets[MAX_SO_STREAMS] = {0}; 10801e04c3fSmrg uint32_t num = 0; 10901e04c3fSmrg 11001e04c3fSmrg for (uint32_t i = 0; i < so->num_outputs; i++) { 11101e04c3fSmrg assert(so->output[i].stream == 0); // @todo 11201e04c3fSmrg uint32_t output_buffer = so->output[i].output_buffer; 11301e04c3fSmrg if (so->output[i].dst_offset != offsets[output_buffer]) { 11401e04c3fSmrg // hole - need to fill 11501e04c3fSmrg state.stream.decl[num].bufferIndex = output_buffer; 11601e04c3fSmrg state.stream.decl[num].hole = true; 11701e04c3fSmrg state.stream.decl[num].componentMask = 11801e04c3fSmrg (1 << (so->output[i].dst_offset - offsets[output_buffer])) 11901e04c3fSmrg - 1; 12001e04c3fSmrg num++; 12101e04c3fSmrg offsets[output_buffer] = so->output[i].dst_offset; 12201e04c3fSmrg } 12301e04c3fSmrg 12401e04c3fSmrg unsigned attrib_slot = so->output[i].register_index; 12501e04c3fSmrg attrib_slot = swr_so_adjust_attrib(attrib_slot, ctx->vs); 12601e04c3fSmrg 12701e04c3fSmrg state.stream.decl[num].bufferIndex = output_buffer; 12801e04c3fSmrg state.stream.decl[num].attribSlot = attrib_slot; 12901e04c3fSmrg state.stream.decl[num].componentMask = 13001e04c3fSmrg ((1 << so->output[i].num_components) - 1) 13101e04c3fSmrg << so->output[i].start_component; 13201e04c3fSmrg state.stream.decl[num].hole = false; 13301e04c3fSmrg num++; 13401e04c3fSmrg 13501e04c3fSmrg offsets[output_buffer] += so->output[i].num_components; 13601e04c3fSmrg } 13701e04c3fSmrg 13801e04c3fSmrg state.stream.numDecls = num; 13901e04c3fSmrg 14001e04c3fSmrg HANDLE hJitMgr = swr_screen(pipe->screen)->hJitMgr; 14101e04c3fSmrg ctx->vs->soFunc[info->mode] = JitCompileStreamout(hJitMgr, state); 14201e04c3fSmrg debug_printf("so shader %p\n", ctx->vs->soFunc[info->mode]); 14301e04c3fSmrg assert(ctx->vs->soFunc[info->mode] && "Error: SoShader = NULL"); 14401e04c3fSmrg } 14501e04c3fSmrg 14601e04c3fSmrg ctx->api.pfnSwrSetSoFunc(ctx->swrContext, ctx->vs->soFunc[info->mode], 0); 14701e04c3fSmrg } 14801e04c3fSmrg 14901e04c3fSmrg struct swr_vertex_element_state *velems = ctx->velems; 15001e04c3fSmrg if (info->primitive_restart) 15101e04c3fSmrg velems->fsState.cutIndex = info->restart_index; 15201e04c3fSmrg else 15301e04c3fSmrg velems->fsState.cutIndex = 0; 15401e04c3fSmrg velems->fsState.bEnableCutIndex = info->primitive_restart; 1557ec681f3Smrg velems->fsState.bPartialVertexBuffer = (info->index_bounds_valid && info->min_index > 0); 15601e04c3fSmrg 15701e04c3fSmrg swr_jit_fetch_key key; 15801e04c3fSmrg swr_generate_fetch_key(key, velems); 15901e04c3fSmrg auto search = velems->map.find(key); 16001e04c3fSmrg if (search != velems->map.end()) { 16101e04c3fSmrg velems->fsFunc = search->second; 16201e04c3fSmrg } else { 16301e04c3fSmrg HANDLE hJitMgr = swr_screen(ctx->pipe.screen)->hJitMgr; 16401e04c3fSmrg velems->fsFunc = JitCompileFetch(hJitMgr, velems->fsState); 16501e04c3fSmrg 16601e04c3fSmrg debug_printf("fetch shader %p\n", velems->fsFunc); 16701e04c3fSmrg assert(velems->fsFunc && "Error: FetchShader = NULL"); 16801e04c3fSmrg 16901e04c3fSmrg velems->map.insert(std::make_pair(key, velems->fsFunc)); 17001e04c3fSmrg } 17101e04c3fSmrg 17201e04c3fSmrg ctx->api.pfnSwrSetFetchFunc(ctx->swrContext, velems->fsFunc); 17301e04c3fSmrg 17401e04c3fSmrg /* Set up frontend state 17501e04c3fSmrg * XXX setup provokingVertex & topologyProvokingVertex */ 17601e04c3fSmrg SWR_FRONTEND_STATE feState = {0}; 17701e04c3fSmrg 17801e04c3fSmrg // feState.vsVertexSize seeds the PA size that is used as an interface 17901e04c3fSmrg // between all the shader stages, so it has to be large enough to 18001e04c3fSmrg // incorporate all interfaces between stages 18101e04c3fSmrg 1827ec681f3Smrg // max of frontend shaders num_outputs 18301e04c3fSmrg feState.vsVertexSize = ctx->vs->info.base.num_outputs; 1847ec681f3Smrg if (ctx->gs) { 1857ec681f3Smrg feState.vsVertexSize = std::max(feState.vsVertexSize, (uint32_t)ctx->gs->info.base.num_outputs); 1867ec681f3Smrg } 1877ec681f3Smrg if (ctx->tcs) { 1887ec681f3Smrg feState.vsVertexSize = std::max(feState.vsVertexSize, (uint32_t)ctx->tcs->info.base.num_outputs); 18901e04c3fSmrg } 1907ec681f3Smrg if (ctx->tes) { 1917ec681f3Smrg feState.vsVertexSize = std::max(feState.vsVertexSize, (uint32_t)ctx->tes->info.base.num_outputs); 1927ec681f3Smrg } 1937ec681f3Smrg 19401e04c3fSmrg 19501e04c3fSmrg if (ctx->vs->info.base.num_outputs) { 19601e04c3fSmrg // gs does not adjust for position in SGV slot at input from vs 1977ec681f3Smrg if (!ctx->gs && !ctx->tcs && !ctx->tes) 19801e04c3fSmrg feState.vsVertexSize--; 19901e04c3fSmrg } 20001e04c3fSmrg 20101e04c3fSmrg // other (non-SGV) slots start at VERTEX_ATTRIB_START_SLOT 20201e04c3fSmrg feState.vsVertexSize += VERTEX_ATTRIB_START_SLOT; 20301e04c3fSmrg 20401e04c3fSmrg // The PA in the clipper does not handle BE vertex sizes 20501e04c3fSmrg // different from FE. Increase vertexsize only for the cases that needed it 20601e04c3fSmrg 20701e04c3fSmrg // primid needs a slot 20801e04c3fSmrg if (ctx->fs->info.base.uses_primid) 20901e04c3fSmrg feState.vsVertexSize++; 21001e04c3fSmrg // sprite coord enable 21101e04c3fSmrg if (ctx->rasterizer->sprite_coord_enable) 21201e04c3fSmrg feState.vsVertexSize++; 21301e04c3fSmrg 21401e04c3fSmrg if (ctx->rasterizer->flatshade_first) { 21501e04c3fSmrg feState.provokingVertex = {1, 0, 0}; 21601e04c3fSmrg } else { 21701e04c3fSmrg feState.provokingVertex = {2, 1, 2}; 21801e04c3fSmrg } 21901e04c3fSmrg 22001e04c3fSmrg enum pipe_prim_type topology; 22101e04c3fSmrg if (ctx->gs) 22201e04c3fSmrg topology = (pipe_prim_type)ctx->gs->info.base.properties[TGSI_PROPERTY_GS_OUTPUT_PRIM]; 22301e04c3fSmrg else 2247ec681f3Smrg topology = (enum pipe_prim_type)info->mode; 22501e04c3fSmrg 22601e04c3fSmrg switch (topology) { 22701e04c3fSmrg case PIPE_PRIM_TRIANGLE_FAN: 22801e04c3fSmrg feState.topologyProvokingVertex = feState.provokingVertex.triFan; 22901e04c3fSmrg break; 23001e04c3fSmrg case PIPE_PRIM_TRIANGLE_STRIP: 23101e04c3fSmrg case PIPE_PRIM_TRIANGLES: 23201e04c3fSmrg feState.topologyProvokingVertex = feState.provokingVertex.triStripList; 23301e04c3fSmrg break; 23401e04c3fSmrg case PIPE_PRIM_QUAD_STRIP: 23501e04c3fSmrg case PIPE_PRIM_QUADS: 23601e04c3fSmrg if (ctx->rasterizer->flatshade_first) 23701e04c3fSmrg feState.topologyProvokingVertex = 0; 23801e04c3fSmrg else 23901e04c3fSmrg feState.topologyProvokingVertex = 3; 24001e04c3fSmrg break; 24101e04c3fSmrg case PIPE_PRIM_LINES: 24201e04c3fSmrg case PIPE_PRIM_LINE_LOOP: 24301e04c3fSmrg case PIPE_PRIM_LINE_STRIP: 24401e04c3fSmrg feState.topologyProvokingVertex = feState.provokingVertex.lineStripList; 24501e04c3fSmrg break; 24601e04c3fSmrg default: 24701e04c3fSmrg feState.topologyProvokingVertex = 0; 24801e04c3fSmrg } 24901e04c3fSmrg 25001e04c3fSmrg feState.bEnableCutIndex = info->primitive_restart; 25101e04c3fSmrg ctx->api.pfnSwrSetFrontendState(ctx->swrContext, &feState); 25201e04c3fSmrg 25301e04c3fSmrg if (info->index_size) 25401e04c3fSmrg ctx->api.pfnSwrDrawIndexedInstanced(ctx->swrContext, 2557ec681f3Smrg swr_convert_prim_topology(info->mode, ctx->patch_vertices), 2567ec681f3Smrg draws[0].count, 25701e04c3fSmrg info->instance_count, 2587ec681f3Smrg draws[0].start, 2597ec681f3Smrg draws->index_bias, 26001e04c3fSmrg info->start_instance); 26101e04c3fSmrg else 26201e04c3fSmrg ctx->api.pfnSwrDrawInstanced(ctx->swrContext, 2637ec681f3Smrg swr_convert_prim_topology(info->mode, ctx->patch_vertices), 2647ec681f3Smrg draws[0].count, 26501e04c3fSmrg info->instance_count, 2667ec681f3Smrg draws[0].start, 26701e04c3fSmrg info->start_instance); 26801e04c3fSmrg 2697ec681f3Smrg /* On client-buffer draw, we used client buffer directly, without 27001e04c3fSmrg * copy. Block until draw is finished. 27101e04c3fSmrg * VMD is an example application that benefits from this. */ 2727ec681f3Smrg if (ctx->dirty & SWR_BLOCK_CLIENT_DRAW) { 27301e04c3fSmrg struct swr_screen *screen = swr_screen(pipe->screen); 27401e04c3fSmrg swr_fence_submit(ctx, screen->flush_fence); 27501e04c3fSmrg swr_fence_finish(pipe->screen, NULL, screen->flush_fence, 0); 27601e04c3fSmrg } 27701e04c3fSmrg} 27801e04c3fSmrg 27901e04c3fSmrg 28001e04c3fSmrgstatic void 28101e04c3fSmrgswr_flush(struct pipe_context *pipe, 28201e04c3fSmrg struct pipe_fence_handle **fence, 28301e04c3fSmrg unsigned flags) 28401e04c3fSmrg{ 28501e04c3fSmrg struct swr_context *ctx = swr_context(pipe); 28601e04c3fSmrg struct swr_screen *screen = swr_screen(pipe->screen); 28701e04c3fSmrg 28801e04c3fSmrg for (int i=0; i < ctx->framebuffer.nr_cbufs; i++) { 28901e04c3fSmrg struct pipe_surface *cb = ctx->framebuffer.cbufs[i]; 29001e04c3fSmrg if (cb) { 29101e04c3fSmrg swr_store_dirty_resource(pipe, cb->texture, SWR_TILE_RESOLVED); 29201e04c3fSmrg } 29301e04c3fSmrg } 29401e04c3fSmrg if (ctx->framebuffer.zsbuf) { 29501e04c3fSmrg swr_store_dirty_resource(pipe, ctx->framebuffer.zsbuf->texture, 29601e04c3fSmrg SWR_TILE_RESOLVED); 29701e04c3fSmrg } 29801e04c3fSmrg 29901e04c3fSmrg if (fence) 30001e04c3fSmrg swr_fence_reference(pipe->screen, fence, screen->flush_fence); 30101e04c3fSmrg} 30201e04c3fSmrg 30301e04c3fSmrgvoid 30401e04c3fSmrgswr_finish(struct pipe_context *pipe) 30501e04c3fSmrg{ 30601e04c3fSmrg struct pipe_fence_handle *fence = nullptr; 30701e04c3fSmrg 30801e04c3fSmrg swr_flush(pipe, &fence, 0); 30901e04c3fSmrg swr_fence_finish(pipe->screen, NULL, fence, 0); 31001e04c3fSmrg swr_fence_reference(pipe->screen, &fence, NULL); 31101e04c3fSmrg} 31201e04c3fSmrg 31301e04c3fSmrg/* 31401e04c3fSmrg * Invalidate tiles so they can be reloaded back when needed 31501e04c3fSmrg */ 31601e04c3fSmrgvoid 31701e04c3fSmrgswr_invalidate_render_target(struct pipe_context *pipe, 31801e04c3fSmrg uint32_t attachment, 31901e04c3fSmrg uint16_t width, uint16_t height) 32001e04c3fSmrg{ 32101e04c3fSmrg struct swr_context *ctx = swr_context(pipe); 32201e04c3fSmrg 32301e04c3fSmrg /* grab the rect from the passed in arguments */ 32401e04c3fSmrg swr_update_draw_context(ctx); 32501e04c3fSmrg SWR_RECT full_rect = 32601e04c3fSmrg {0, 0, (int32_t)width, (int32_t)height}; 32701e04c3fSmrg ctx->api.pfnSwrInvalidateTiles(ctx->swrContext, 32801e04c3fSmrg 1 << attachment, 32901e04c3fSmrg full_rect); 33001e04c3fSmrg} 33101e04c3fSmrg 33201e04c3fSmrg 33301e04c3fSmrg/* 33401e04c3fSmrg * Store SWR HotTiles back to renderTarget surface. 33501e04c3fSmrg */ 33601e04c3fSmrgvoid 33701e04c3fSmrgswr_store_render_target(struct pipe_context *pipe, 33801e04c3fSmrg uint32_t attachment, 33901e04c3fSmrg enum SWR_TILE_STATE post_tile_state) 34001e04c3fSmrg{ 34101e04c3fSmrg struct swr_context *ctx = swr_context(pipe); 34201e04c3fSmrg struct swr_draw_context *pDC = &ctx->swrDC; 34301e04c3fSmrg struct SWR_SURFACE_STATE *renderTarget = &pDC->renderTargets[attachment]; 34401e04c3fSmrg 34501e04c3fSmrg /* Only proceed if there's a valid surface to store to */ 34601e04c3fSmrg if (renderTarget->xpBaseAddress) { 34701e04c3fSmrg swr_update_draw_context(ctx); 34801e04c3fSmrg SWR_RECT full_rect = 34901e04c3fSmrg {0, 0, 35001e04c3fSmrg (int32_t)u_minify(renderTarget->width, renderTarget->lod), 35101e04c3fSmrg (int32_t)u_minify(renderTarget->height, renderTarget->lod)}; 35201e04c3fSmrg ctx->api.pfnSwrStoreTiles(ctx->swrContext, 35301e04c3fSmrg 1 << attachment, 35401e04c3fSmrg post_tile_state, 35501e04c3fSmrg full_rect); 35601e04c3fSmrg } 35701e04c3fSmrg} 35801e04c3fSmrg 35901e04c3fSmrgvoid 36001e04c3fSmrgswr_store_dirty_resource(struct pipe_context *pipe, 36101e04c3fSmrg struct pipe_resource *resource, 36201e04c3fSmrg enum SWR_TILE_STATE post_tile_state) 36301e04c3fSmrg{ 36401e04c3fSmrg /* Only store resource if it has been written to */ 36501e04c3fSmrg if (swr_resource(resource)->status & SWR_RESOURCE_WRITE) { 36601e04c3fSmrg struct swr_context *ctx = swr_context(pipe); 36701e04c3fSmrg struct swr_screen *screen = swr_screen(pipe->screen); 36801e04c3fSmrg struct swr_resource *spr = swr_resource(resource); 36901e04c3fSmrg 37001e04c3fSmrg swr_draw_context *pDC = &ctx->swrDC; 37101e04c3fSmrg SWR_SURFACE_STATE *renderTargets = pDC->renderTargets; 37201e04c3fSmrg for (uint32_t i = 0; i < SWR_NUM_ATTACHMENTS; i++) 37301e04c3fSmrg if (renderTargets[i].xpBaseAddress == spr->swr.xpBaseAddress || 37401e04c3fSmrg (spr->secondary.xpBaseAddress && 37501e04c3fSmrg renderTargets[i].xpBaseAddress == spr->secondary.xpBaseAddress)) { 37601e04c3fSmrg swr_store_render_target(pipe, i, post_tile_state); 37701e04c3fSmrg 37801e04c3fSmrg /* Mesa thinks depth/stencil are fused, so we'll never get an 37901e04c3fSmrg * explicit resource for stencil. So, if checking depth, then 38001e04c3fSmrg * also check for stencil. */ 38101e04c3fSmrg if (spr->has_stencil && (i == SWR_ATTACHMENT_DEPTH)) { 38201e04c3fSmrg swr_store_render_target( 38301e04c3fSmrg pipe, SWR_ATTACHMENT_STENCIL, post_tile_state); 38401e04c3fSmrg } 38501e04c3fSmrg 38601e04c3fSmrg /* This fence signals StoreTiles completion */ 38701e04c3fSmrg swr_fence_submit(ctx, screen->flush_fence); 38801e04c3fSmrg 38901e04c3fSmrg break; 39001e04c3fSmrg } 39101e04c3fSmrg } 39201e04c3fSmrg} 39301e04c3fSmrg 39401e04c3fSmrgvoid 39501e04c3fSmrgswr_draw_init(struct pipe_context *pipe) 39601e04c3fSmrg{ 39701e04c3fSmrg pipe->draw_vbo = swr_draw_vbo; 39801e04c3fSmrg pipe->flush = swr_flush; 39901e04c3fSmrg} 400