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 #include "util/u_upload_mgr.h" 28 29 #include "nv_object.xml.h" 30 #include "nv30/nv30-40_3d.xml.h" 31 32 #include "nouveau_fence.h" 33 #include "nv30/nv30_context.h" 34 #include "nv30/nv30_transfer.h" 35 #include "nv30/nv30_state.h" 36 37 static void 38 nv30_context_kick_notify(struct nouveau_pushbuf *push) 39 { 40 struct nouveau_screen *screen; 41 struct nv30_context *nv30; 42 43 if (!push->user_priv) 44 return; 45 nv30 = container_of(push->user_priv, nv30, bufctx); 46 screen = &nv30->screen->base; 47 48 nouveau_fence_next(screen); 49 nouveau_fence_update(screen, true); 50 51 if (push->bufctx) { 52 struct nouveau_bufref *bref; 53 LIST_FOR_EACH_ENTRY(bref, &push->bufctx->current, thead) { 54 struct nv04_resource *res = bref->priv; 55 if (res && res->mm) { 56 nouveau_fence_ref(screen->fence.current, &res->fence); 57 58 if (bref->flags & NOUVEAU_BO_RD) 59 res->status |= NOUVEAU_BUFFER_STATUS_GPU_READING; 60 61 if (bref->flags & NOUVEAU_BO_WR) { 62 nouveau_fence_ref(screen->fence.current, &res->fence_wr); 63 res->status |= NOUVEAU_BUFFER_STATUS_GPU_WRITING | 64 NOUVEAU_BUFFER_STATUS_DIRTY; 65 } 66 } 67 } 68 } 69 } 70 71 static void 72 nv30_context_flush(struct pipe_context *pipe, struct pipe_fence_handle **fence, 73 unsigned flags) 74 { 75 struct nv30_context *nv30 = nv30_context(pipe); 76 struct nouveau_pushbuf *push = nv30->base.pushbuf; 77 78 if (fence) 79 nouveau_fence_ref(nv30->screen->base.fence.current, 80 (struct nouveau_fence **)fence); 81 82 PUSH_KICK(push); 83 84 nouveau_context_update_frame_stats(&nv30->base); 85 } 86 87 static int 88 nv30_invalidate_resource_storage(struct nouveau_context *nv, 89 struct pipe_resource *res, 90 int ref) 91 { 92 struct nv30_context *nv30 = nv30_context(&nv->pipe); 93 unsigned i; 94 95 if (res->bind & PIPE_BIND_RENDER_TARGET) { 96 for (i = 0; i < nv30->framebuffer.nr_cbufs; ++i) { 97 if (nv30->framebuffer.cbufs[i] && 98 nv30->framebuffer.cbufs[i]->texture == res) { 99 nv30->dirty |= NV30_NEW_FRAMEBUFFER; 100 nouveau_bufctx_reset(nv30->bufctx, BUFCTX_FB); 101 if (!--ref) 102 return ref; 103 } 104 } 105 } 106 if (res->bind & PIPE_BIND_DEPTH_STENCIL) { 107 if (nv30->framebuffer.zsbuf && 108 nv30->framebuffer.zsbuf->texture == res) { 109 nv30->dirty |= NV30_NEW_FRAMEBUFFER; 110 nouveau_bufctx_reset(nv30->bufctx, BUFCTX_FB); 111 if (!--ref) 112 return ref; 113 } 114 } 115 116 if (res->bind & PIPE_BIND_VERTEX_BUFFER) { 117 for (i = 0; i < nv30->num_vtxbufs; ++i) { 118 if (nv30->vtxbuf[i].buffer.resource == res) { 119 nv30->dirty |= NV30_NEW_ARRAYS; 120 nouveau_bufctx_reset(nv30->bufctx, BUFCTX_VTXBUF); 121 if (!--ref) 122 return ref; 123 } 124 } 125 } 126 127 if (res->bind & PIPE_BIND_SAMPLER_VIEW) { 128 for (i = 0; i < nv30->fragprog.num_textures; ++i) { 129 if (nv30->fragprog.textures[i] && 130 nv30->fragprog.textures[i]->texture == res) { 131 nv30->dirty |= NV30_NEW_FRAGTEX; 132 nouveau_bufctx_reset(nv30->bufctx, BUFCTX_FRAGTEX(i)); 133 if (!--ref) 134 return ref; 135 } 136 } 137 for (i = 0; i < nv30->vertprog.num_textures; ++i) { 138 if (nv30->vertprog.textures[i] && 139 nv30->vertprog.textures[i]->texture == res) { 140 nv30->dirty |= NV30_NEW_VERTTEX; 141 nouveau_bufctx_reset(nv30->bufctx, BUFCTX_VERTTEX(i)); 142 if (!--ref) 143 return ref; 144 } 145 } 146 } 147 148 return ref; 149 } 150 151 static void 152 nv30_context_destroy(struct pipe_context *pipe) 153 { 154 struct nv30_context *nv30 = nv30_context(pipe); 155 156 if (nv30->blitter) 157 util_blitter_destroy(nv30->blitter); 158 159 if (nv30->draw) 160 draw_destroy(nv30->draw); 161 162 if (nv30->base.pipe.stream_uploader) 163 u_upload_destroy(nv30->base.pipe.stream_uploader); 164 165 if (nv30->blit_vp) 166 nouveau_heap_free(&nv30->blit_vp); 167 168 if (nv30->blit_fp) 169 pipe_resource_reference(&nv30->blit_fp, NULL); 170 171 if (nv30->screen->base.pushbuf->user_priv == &nv30->bufctx) 172 nv30->screen->base.pushbuf->user_priv = NULL; 173 174 nouveau_bufctx_del(&nv30->bufctx); 175 176 if (nv30->screen->cur_ctx == nv30) 177 nv30->screen->cur_ctx = NULL; 178 179 nouveau_context_destroy(&nv30->base); 180 } 181 182 #define FAIL_CONTEXT_INIT(str, err) \ 183 do { \ 184 NOUVEAU_ERR(str, err); \ 185 nv30_context_destroy(pipe); \ 186 return NULL; \ 187 } while(0) 188 189 struct pipe_context * 190 nv30_context_create(struct pipe_screen *pscreen, void *priv, unsigned ctxflags) 191 { 192 struct nv30_screen *screen = nv30_screen(pscreen); 193 struct nv30_context *nv30 = CALLOC_STRUCT(nv30_context); 194 struct nouveau_pushbuf *push; 195 struct pipe_context *pipe; 196 int ret; 197 198 if (!nv30) 199 return NULL; 200 201 nv30->screen = screen; 202 nv30->base.screen = &screen->base; 203 nv30->base.copy_data = nv30_transfer_copy_data; 204 205 pipe = &nv30->base.pipe; 206 pipe->screen = pscreen; 207 pipe->priv = priv; 208 pipe->destroy = nv30_context_destroy; 209 pipe->flush = nv30_context_flush; 210 211 nv30->base.pipe.stream_uploader = u_upload_create_default(&nv30->base.pipe); 212 if (!nv30->base.pipe.stream_uploader) { 213 nv30_context_destroy(pipe); 214 return NULL; 215 } 216 nv30->base.pipe.const_uploader = nv30->base.pipe.stream_uploader; 217 218 /*XXX: *cough* per-context client */ 219 nv30->base.client = screen->base.client; 220 221 /*XXX: *cough* per-context pushbufs */ 222 push = screen->base.pushbuf; 223 nv30->base.pushbuf = push; 224 nv30->base.pushbuf->user_priv = &nv30->bufctx; /* hack at validate time */ 225 nv30->base.pushbuf->rsvd_kick = 16; /* hack in screen before first space */ 226 nv30->base.pushbuf->kick_notify = nv30_context_kick_notify; 227 228 nv30->base.invalidate_resource_storage = nv30_invalidate_resource_storage; 229 230 ret = nouveau_bufctx_new(nv30->base.client, 64, &nv30->bufctx); 231 if (ret) { 232 nv30_context_destroy(pipe); 233 return NULL; 234 } 235 236 /*XXX: make configurable with performance vs quality, these defaults 237 * match the binary driver's defaults 238 */ 239 if (screen->eng3d->oclass < NV40_3D_CLASS) 240 nv30->config.filter = 0x00000004; 241 else 242 nv30->config.filter = 0x00002dc4; 243 244 nv30->config.aniso = NV40_3D_TEX_WRAP_ANISO_MIP_FILTER_OPTIMIZATION_OFF; 245 246 if (debug_get_bool_option("NV30_SWTNL", false)) 247 nv30->draw_flags |= NV30_NEW_SWTNL; 248 249 nouveau_context_init(&nv30->base); 250 nv30->sample_mask = 0xffff; 251 nv30_vbo_init(pipe); 252 nv30_query_init(pipe); 253 nv30_state_init(pipe); 254 nv30_resource_init(pipe); 255 nv30_clear_init(pipe); 256 nv30_fragprog_init(pipe); 257 nv30_vertprog_init(pipe); 258 nv30_texture_init(pipe); 259 nv30_fragtex_init(pipe); 260 nv40_verttex_init(pipe); 261 nv30_draw_init(pipe); 262 263 nv30->blitter = util_blitter_create(pipe); 264 if (!nv30->blitter) { 265 nv30_context_destroy(pipe); 266 return NULL; 267 } 268 269 nouveau_context_init_vdec(&nv30->base); 270 271 return pipe; 272 } 273