1 /* 2 * Copyright 2012 Red Hat Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 * 22 * Authors: Ben Skeggs 23 * 24 */ 25 26 #include "draw/draw_context.h" 27 28 #include "nv_object.xml.h" 29 #include "nv30/nv30-40_3d.xml.h" 30 31 #include "nouveau_fence.h" 32 #include "nv30/nv30_context.h" 33 #include "nv30/nv30_transfer.h" 34 #include "nv30/nv30_state.h" 35 36 static void 37 nv30_context_kick_notify(struct nouveau_pushbuf *push) 38 { 39 struct nouveau_screen *screen; 40 struct nv30_context *nv30; 41 42 if (!push->user_priv) 43 return; 44 nv30 = container_of(push->user_priv, nv30, bufctx); 45 screen = &nv30->screen->base; 46 47 nouveau_fence_next(screen); 48 nouveau_fence_update(screen, true); 49 50 if (push->bufctx) { 51 struct nouveau_bufref *bref; 52 LIST_FOR_EACH_ENTRY(bref, &push->bufctx->current, thead) { 53 struct nv04_resource *res = bref->priv; 54 if (res && res->mm) { 55 nouveau_fence_ref(screen->fence.current, &res->fence); 56 57 if (bref->flags & NOUVEAU_BO_RD) 58 res->status |= NOUVEAU_BUFFER_STATUS_GPU_READING; 59 60 if (bref->flags & NOUVEAU_BO_WR) { 61 nouveau_fence_ref(screen->fence.current, &res->fence_wr); 62 res->status |= NOUVEAU_BUFFER_STATUS_GPU_WRITING | 63 NOUVEAU_BUFFER_STATUS_DIRTY; 64 } 65 } 66 } 67 } 68 } 69 70 static void 71 nv30_context_flush(struct pipe_context *pipe, struct pipe_fence_handle **fence, 72 unsigned flags) 73 { 74 struct nv30_context *nv30 = nv30_context(pipe); 75 struct nouveau_pushbuf *push = nv30->base.pushbuf; 76 77 if (fence) 78 nouveau_fence_ref(nv30->screen->base.fence.current, 79 (struct nouveau_fence **)fence); 80 81 PUSH_KICK(push); 82 83 nouveau_context_update_frame_stats(&nv30->base); 84 } 85 86 static int 87 nv30_invalidate_resource_storage(struct nouveau_context *nv, 88 struct pipe_resource *res, 89 int ref) 90 { 91 struct nv30_context *nv30 = nv30_context(&nv->pipe); 92 unsigned i; 93 94 if (res->bind & PIPE_BIND_RENDER_TARGET) { 95 for (i = 0; i < nv30->framebuffer.nr_cbufs; ++i) { 96 if (nv30->framebuffer.cbufs[i] && 97 nv30->framebuffer.cbufs[i]->texture == res) { 98 nv30->dirty |= NV30_NEW_FRAMEBUFFER; 99 nouveau_bufctx_reset(nv30->bufctx, BUFCTX_FB); 100 if (!--ref) 101 return ref; 102 } 103 } 104 } 105 if (res->bind & PIPE_BIND_DEPTH_STENCIL) { 106 if (nv30->framebuffer.zsbuf && 107 nv30->framebuffer.zsbuf->texture == res) { 108 nv30->dirty |= NV30_NEW_FRAMEBUFFER; 109 nouveau_bufctx_reset(nv30->bufctx, BUFCTX_FB); 110 if (!--ref) 111 return ref; 112 } 113 } 114 115 if (res->bind & PIPE_BIND_VERTEX_BUFFER) { 116 for (i = 0; i < nv30->num_vtxbufs; ++i) { 117 if (nv30->vtxbuf[i].buffer == res) { 118 nv30->dirty |= NV30_NEW_ARRAYS; 119 nouveau_bufctx_reset(nv30->bufctx, BUFCTX_VTXBUF); 120 if (!--ref) 121 return ref; 122 } 123 } 124 } 125 if (res->bind & PIPE_BIND_INDEX_BUFFER) { 126 if (nv30->idxbuf.buffer == res) { 127 nouveau_bufctx_reset(nv30->bufctx, BUFCTX_IDXBUF); 128 if (!--ref) 129 return ref; 130 } 131 } 132 133 if (res->bind & PIPE_BIND_SAMPLER_VIEW) { 134 for (i = 0; i < nv30->fragprog.num_textures; ++i) { 135 if (nv30->fragprog.textures[i] && 136 nv30->fragprog.textures[i]->texture == res) { 137 nv30->dirty |= NV30_NEW_FRAGTEX; 138 nouveau_bufctx_reset(nv30->bufctx, BUFCTX_FRAGTEX(i)); 139 if (!--ref) 140 return ref; 141 } 142 } 143 for (i = 0; i < nv30->vertprog.num_textures; ++i) { 144 if (nv30->vertprog.textures[i] && 145 nv30->vertprog.textures[i]->texture == res) { 146 nv30->dirty |= NV30_NEW_VERTTEX; 147 nouveau_bufctx_reset(nv30->bufctx, BUFCTX_VERTTEX(i)); 148 if (!--ref) 149 return ref; 150 } 151 } 152 } 153 154 return ref; 155 } 156 157 static void 158 nv30_context_destroy(struct pipe_context *pipe) 159 { 160 struct nv30_context *nv30 = nv30_context(pipe); 161 162 if (nv30->blitter) 163 util_blitter_destroy(nv30->blitter); 164 165 if (nv30->draw) 166 draw_destroy(nv30->draw); 167 168 if (nv30->blit_vp) 169 nouveau_heap_free(&nv30->blit_vp); 170 171 if (nv30->blit_fp) 172 pipe_resource_reference(&nv30->blit_fp, NULL); 173 174 if (nv30->screen->base.pushbuf->user_priv == &nv30->bufctx) 175 nv30->screen->base.pushbuf->user_priv = NULL; 176 177 nouveau_bufctx_del(&nv30->bufctx); 178 179 if (nv30->screen->cur_ctx == nv30) 180 nv30->screen->cur_ctx = NULL; 181 182 nouveau_context_destroy(&nv30->base); 183 } 184 185 #define FAIL_CONTEXT_INIT(str, err) \ 186 do { \ 187 NOUVEAU_ERR(str, err); \ 188 nv30_context_destroy(pipe); \ 189 return NULL; \ 190 } while(0) 191 192 struct pipe_context * 193 nv30_context_create(struct pipe_screen *pscreen, void *priv, unsigned ctxflags) 194 { 195 struct nv30_screen *screen = nv30_screen(pscreen); 196 struct nv30_context *nv30 = CALLOC_STRUCT(nv30_context); 197 struct nouveau_pushbuf *push; 198 struct pipe_context *pipe; 199 int ret; 200 201 if (!nv30) 202 return NULL; 203 204 nv30->screen = screen; 205 nv30->base.screen = &screen->base; 206 nv30->base.copy_data = nv30_transfer_copy_data; 207 208 pipe = &nv30->base.pipe; 209 pipe->screen = pscreen; 210 pipe->priv = priv; 211 pipe->destroy = nv30_context_destroy; 212 pipe->flush = nv30_context_flush; 213 214 /*XXX: *cough* per-context client */ 215 nv30->base.client = screen->base.client; 216 217 /*XXX: *cough* per-context pushbufs */ 218 push = screen->base.pushbuf; 219 nv30->base.pushbuf = push; 220 nv30->base.pushbuf->user_priv = &nv30->bufctx; /* hack at validate time */ 221 nv30->base.pushbuf->rsvd_kick = 16; /* hack in screen before first space */ 222 nv30->base.pushbuf->kick_notify = nv30_context_kick_notify; 223 224 nv30->base.invalidate_resource_storage = nv30_invalidate_resource_storage; 225 226 ret = nouveau_bufctx_new(nv30->base.client, 64, &nv30->bufctx); 227 if (ret) { 228 nv30_context_destroy(pipe); 229 return NULL; 230 } 231 232 /*XXX: make configurable with performance vs quality, these defaults 233 * match the binary driver's defaults 234 */ 235 if (screen->eng3d->oclass < NV40_3D_CLASS) 236 nv30->config.filter = 0x00000004; 237 else 238 nv30->config.filter = 0x00002dc4; 239 240 nv30->config.aniso = NV40_3D_TEX_WRAP_ANISO_MIP_FILTER_OPTIMIZATION_OFF; 241 242 if (debug_get_bool_option("NV30_SWTNL", false)) 243 nv30->draw_flags |= NV30_NEW_SWTNL; 244 245 nouveau_context_init(&nv30->base); 246 nv30->sample_mask = 0xffff; 247 nv30_vbo_init(pipe); 248 nv30_query_init(pipe); 249 nv30_state_init(pipe); 250 nv30_resource_init(pipe); 251 nv30_clear_init(pipe); 252 nv30_fragprog_init(pipe); 253 nv30_vertprog_init(pipe); 254 nv30_texture_init(pipe); 255 nv30_fragtex_init(pipe); 256 nv40_verttex_init(pipe); 257 nv30_draw_init(pipe); 258 259 nv30->blitter = util_blitter_create(pipe); 260 if (!nv30->blitter) { 261 nv30_context_destroy(pipe); 262 return NULL; 263 } 264 265 nouveau_context_init_vdec(&nv30->base); 266 267 return pipe; 268 } 269