| @@ -84,6 +84,14 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |||
| #define NVC0_3D_EARLY_FRAGMENT_TESTS 0x00000210 | |||
| #define NVC0_3D_MEM_BARRIER 0x0000021c | |||
| #define NVC0_3D_MEM_BARRIER_UNK0 0x00000001 | |||
| #define NVC0_3D_MEM_BARRIER_UNK1 0x00000002 | |||
| #define NVC0_3D_MEM_BARRIER_UNK2 0x00000004 | |||
| #define NVC0_3D_MEM_BARRIER_UNK4 0x00000010 | |||
| #define NVC0_3D_MEM_BARRIER_UNK8 0x00000100 | |||
| #define NVC0_3D_MEM_BARRIER_UNK12 0x00001000 | |||
| #define NVC0_3D_TESS_MODE 0x00000320 | |||
| #define NVC0_3D_TESS_MODE_PRIM__MASK 0x0000000f | |||
| #define NVC0_3D_TESS_MODE_PRIM__SHIFT 0 | |||
| @@ -122,11 +130,17 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |||
| #define NVC0_3D_TFB_PRIMITIVE_ID(i0) (0x00000390 + 0x20*(i0)) | |||
| #define NVC0_3D_TFB_UNK0700(i0) (0x00000700 + 0x10*(i0)) | |||
| #define NVC0_3D_TFB_UNK07X0(i0) (0x00000700 + 0x10*(i0)) | |||
| #define NVC0_3D_TFB_UNK07X0__ESIZE 0x00000010 | |||
| #define NVC0_3D_TFB_UNK07X0__LEN 0x00000004 | |||
| #define NVC0_3D_TFB_VARYING_COUNT(i0) (0x00000704 + 0x10*(i0)) | |||
| #define NVC0_3D_TFB_VARYING_COUNT__ESIZE 0x00000010 | |||
| #define NVC0_3D_TFB_VARYING_COUNT__LEN 0x00000004 | |||
| #define NVC0_3D_TFB_BUFFER_STRIDE(i0) (0x00000708 + 0x10*(i0)) | |||
| #define NVC0_3D_TFB_BUFFER_STRIDE__ESIZE 0x00000010 | |||
| #define NVC0_3D_TFB_BUFFER_STRIDE__LEN 0x00000004 | |||
| #define NVC0_3D_TFB_ENABLE 0x00000744 | |||
| @@ -1157,9 +1171,9 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |||
| #define NVC0_3D_VERT_COLOR_CLAMP_EN 0x00002600 | |||
| #define NVC0_3D_TFB_VARYING_LOCS(i0) (0x00002800 + 0x4*(i0)) | |||
| #define NVC0_3D_TFB_VARYING_LOCS(i0, i1) (0x00002800 + 0x80*(i0) + 0x4*(i1)) | |||
| #define NVC0_3D_TFB_VARYING_LOCS__ESIZE 0x00000004 | |||
| #define NVC0_3D_TFB_VARYING_LOCS__LEN 0x00000080 | |||
| #define NVC0_3D_TFB_VARYING_LOCS__LEN 0x00000020 | |||
| #define NVC0_3D_COLOR_MASK_BROADCAST 0x00003808 | |||
| @@ -54,6 +54,8 @@ | |||
| #define NVC0_NEW_CONSTBUF (1 << 18) | |||
| #define NVC0_NEW_TEXTURES (1 << 19) | |||
| #define NVC0_NEW_SAMPLERS (1 << 20) | |||
| #define NVC0_NEW_TFB (1 << 21) | |||
| #define NVC0_NEW_TFB_BUFFERS (1 << 22) | |||
| #define NVC0_BUFCTX_CONSTANT 0 | |||
| #define NVC0_BUFCTX_FRAME 1 | |||
| @@ -123,6 +125,11 @@ struct nvc0_context { | |||
| boolean vbo_dirty; | |||
| boolean vbo_push_hint; | |||
| struct nvc0_transform_feedback_state *tfb; | |||
| struct pipe_resource *tfbbuf[4]; | |||
| unsigned num_tfbbufs; | |||
| unsigned tfb_offset[4]; | |||
| struct draw_context *draw; | |||
| }; | |||
| @@ -177,6 +184,8 @@ void nvc0_tevlprog_validate(struct nvc0_context *); | |||
| void nvc0_gmtyprog_validate(struct nvc0_context *); | |||
| void nvc0_fragprog_validate(struct nvc0_context *); | |||
| void nvc0_tfb_validate(struct nvc0_context *); | |||
| /* nvc0_state.c */ | |||
| extern void nvc0_init_state_functions(struct nvc0_context *); | |||
| @@ -55,7 +55,7 @@ nvc0_program_validate(struct nvc0_context *nvc0, struct nvc0_program *prog) | |||
| prog->code_base + NVC0_SHADER_HEADER_SIZE, | |||
| prog->code_size, prog->code); | |||
| BEGIN_RING(nvc0->screen->base.channel, RING_3D_(0x021c), 1); | |||
| BEGIN_RING(nvc0->screen->base.channel, RING_3D(MEM_BARRIER), 1); | |||
| OUT_RING (nvc0->screen->base.channel, 0x1111); | |||
| return TRUE; | |||
| @@ -178,3 +178,59 @@ nvc0_gmtyprog_validate(struct nvc0_context *nvc0) | |||
| BEGIN_RING(chan, RING_3D(SP_GPR_ALLOC(4)), 1); | |||
| OUT_RING (chan, gp->max_gpr); | |||
| } | |||
| /* It's *is* kind of shader related. We need to inspect the program | |||
| * to get the output locations right. | |||
| */ | |||
| void | |||
| nvc0_tfb_validate(struct nvc0_context *nvc0) | |||
| { | |||
| struct nouveau_channel *chan = nvc0->screen->base.channel; | |||
| struct nvc0_program *vp; | |||
| struct nvc0_transform_feedback_state *tfb = nvc0->tfb; | |||
| int b; | |||
| BEGIN_RING(chan, RING_3D(TFB_ENABLE), 1); | |||
| if (!tfb) { | |||
| OUT_RING(chan, 0); | |||
| return; | |||
| } | |||
| OUT_RING(chan, 1); | |||
| vp = nvc0->vertprog ? nvc0->vertprog : nvc0->gmtyprog; | |||
| for (b = 0; b < nvc0->num_tfbbufs; ++b) { | |||
| uint8_t idx, var[128]; | |||
| int i, n; | |||
| struct nvc0_resource *buf = nvc0_resource(nvc0->tfbbuf[b]); | |||
| BEGIN_RING(chan, RING_3D(TFB_BUFFER_ENABLE(b)), 5); | |||
| OUT_RING (chan, 1); | |||
| OUT_RESRCh(chan, buf, nvc0->tfb_offset[b], NOUVEAU_BO_WR); | |||
| OUT_RESRCl(chan, buf, nvc0->tfb_offset[b], NOUVEAU_BO_WR); | |||
| OUT_RING (chan, buf->base.width0 - nvc0->tfb_offset[b]); | |||
| OUT_RING (chan, 0); /* TFB_PRIMITIVE_ID <- offset ? */ | |||
| if (!(nvc0->dirty & NVC0_NEW_TFB)) | |||
| continue; | |||
| BEGIN_RING(chan, RING_3D(TFB_UNK07X0(b)), 3); | |||
| OUT_RING (chan, 0); | |||
| OUT_RING (chan, tfb->varying_count[b]); | |||
| OUT_RING (chan, tfb->stride[b]); | |||
| n = b ? tfb->varying_count[b - 1] : 0; | |||
| i = 0; | |||
| for (; i < tfb->varying_count[b]; ++i) { | |||
| idx = tfb->varying_index[n + i]; | |||
| var[i] = vp->vp.out_pos[idx >> 2] + (idx & 3); | |||
| } | |||
| for (; i & 3; ++i) | |||
| var[i] = 0; | |||
| BEGIN_RING(chan, RING_3D(TFB_VARYING_LOCS(b, 0)), i / 4); | |||
| OUT_RINGp (chan, var, i / 4); | |||
| } | |||
| for (; b < 4; ++b) | |||
| IMMED_RING(chan, RING_3D(TFB_BUFFER_ENABLE(b)), 0); | |||
| } | |||
| @@ -808,6 +808,74 @@ nvc0_vertex_state_bind(struct pipe_context *pipe, void *hwcso) | |||
| nvc0->dirty |= NVC0_NEW_VERTEX; | |||
| } | |||
| static void * | |||
| nvc0_tfb_state_create(struct pipe_context *pipe, | |||
| const struct pipe_stream_output_state *pso) | |||
| { | |||
| struct nvc0_transform_feedback_state *so; | |||
| int n = 0; | |||
| int i, c, b; | |||
| so = MALLOC(sizeof(*so) + pso->num_outputs * 4 * sizeof(uint8_t)); | |||
| if (!so) | |||
| return NULL; | |||
| for (b = 0; b < 4; ++b) { | |||
| for (i = 0; i < pso->num_outputs; ++i) { | |||
| if (pso->output_buffer[i] != b) | |||
| continue; | |||
| for (c = 0; c < 4; ++c) { | |||
| if (!(pso->register_mask[i] & (1 << c))) | |||
| continue; | |||
| so->varying_count[b]++; | |||
| so->varying_index[n++] = (pso->register_index[i] << 2) | c; | |||
| } | |||
| } | |||
| so->stride[b] = so->varying_count[b] * 4; | |||
| } | |||
| if (pso->stride) | |||
| so->stride[0] = pso->stride; | |||
| return so; | |||
| } | |||
| static void | |||
| nvc0_tfb_state_delete(struct pipe_context *pipe, void *hwcso) | |||
| { | |||
| FREE(hwcso); | |||
| } | |||
| static void | |||
| nvc0_tfb_state_bind(struct pipe_context *pipe, void *hwcso) | |||
| { | |||
| nvc0_context(pipe)->tfb = hwcso; | |||
| nvc0_context(pipe)->dirty |= NVC0_NEW_TFB; | |||
| } | |||
| static void | |||
| nvc0_set_transform_feedback_buffers(struct pipe_context *pipe, | |||
| struct pipe_resource **buffers, | |||
| int *offsets, | |||
| int num_buffers) | |||
| { | |||
| struct nvc0_context *nvc0 = nvc0_context(pipe); | |||
| int i; | |||
| assert(num_buffers >= 0 && num_buffers <= 4); /* why signed ? */ | |||
| for (i = 0; i < num_buffers; ++i) { | |||
| assert(offsets[i] >= 0); | |||
| nvc0->tfb_offset[i] = offsets[i]; | |||
| pipe_resource_reference(&nvc0->tfbbuf[i], buffers[i]); | |||
| } | |||
| for (; i < nvc0->num_tfbbufs; ++i) | |||
| pipe_resource_reference(&nvc0->tfbbuf[i], NULL); | |||
| nvc0->num_tfbbufs = num_buffers; | |||
| nvc0->dirty |= NVC0_NEW_TFB_BUFFERS; | |||
| } | |||
| void | |||
| nvc0_init_state_functions(struct nvc0_context *nvc0) | |||
| { | |||
| @@ -861,5 +929,10 @@ nvc0_init_state_functions(struct nvc0_context *nvc0) | |||
| nvc0->pipe.set_vertex_buffers = nvc0_set_vertex_buffers; | |||
| nvc0->pipe.set_index_buffer = nvc0_set_index_buffer; | |||
| nvc0->pipe.create_stream_output_state = nvc0_tfb_state_create; | |||
| nvc0->pipe.delete_stream_output_state = nvc0_tfb_state_delete; | |||
| nvc0->pipe.bind_stream_output_state = nvc0_tfb_state_bind; | |||
| nvc0->pipe.set_stream_output_buffers = nvc0_set_transform_feedback_buffers; | |||
| } | |||
| @@ -436,7 +436,8 @@ static struct state_validate { | |||
| { nvc0_constbufs_validate, NVC0_NEW_CONSTBUF }, | |||
| { nvc0_validate_textures, NVC0_NEW_TEXTURES }, | |||
| { nvc0_validate_samplers, NVC0_NEW_SAMPLERS }, | |||
| { nvc0_vertex_arrays_validate, NVC0_NEW_VERTEX | NVC0_NEW_ARRAYS } | |||
| { nvc0_vertex_arrays_validate, NVC0_NEW_VERTEX | NVC0_NEW_ARRAYS }, | |||
| { nvc0_tfb_validate, NVC0_NEW_TFB | NVC0_NEW_TFB_BUFFERS } | |||
| }; | |||
| #define validate_list_len (sizeof(validate_list) / sizeof(validate_list[0])) | |||
| @@ -69,14 +69,14 @@ struct nvc0_vertex_stateobj { | |||
| uint32_t instance_bufs; | |||
| unsigned vtx_size; | |||
| unsigned vtx_per_packet_max; | |||
| struct nvc0_vertex_element element[1]; | |||
| struct nvc0_vertex_element element[0]; | |||
| }; | |||
| /* will have to lookup index -> location qualifier from nvc0_program */ | |||
| struct nvc0_tfb_state { | |||
| uint8_t varying_count[4]; | |||
| struct nvc0_transform_feedback_state { | |||
| uint32_t stride[4]; | |||
| uint8_t varying_indices[1]; | |||
| uint8_t varying_count[4]; | |||
| uint8_t varying_index[0]; | |||
| }; | |||
| #endif | |||
| @@ -54,7 +54,7 @@ nvc0_vertex_state_create(struct pipe_context *pipe, | |||
| assert(num_elements); | |||
| so = MALLOC(sizeof(*so) + | |||
| (num_elements - 1) * sizeof(struct nvc0_vertex_element)); | |||
| num_elements * sizeof(struct nvc0_vertex_element)); | |||
| if (!so) | |||
| return NULL; | |||
| so->num_elements = num_elements; | |||
| @@ -351,55 +351,6 @@ nvc0_draw_vbo_flush_notify(struct nouveau_channel *chan) | |||
| nvc0_bufctx_emit_relocs(nvc0); | |||
| } | |||
| #if 0 | |||
| static struct nouveau_bo * | |||
| nvc0_tfb_setup(struct nvc0_context *nvc0) | |||
| { | |||
| struct nouveau_channel *chan = nvc0->screen->base.channel; | |||
| struct nouveau_bo *tfb = NULL; | |||
| int ret, i; | |||
| ret = nouveau_bo_new(nvc0->screen->base.device, | |||
| NOUVEAU_BO_GART | NOUVEAU_BO_MAP, 0, 4096, &tfb); | |||
| if (ret) | |||
| return NULL; | |||
| ret = nouveau_bo_map(tfb, NOUVEAU_BO_WR); | |||
| if (ret) | |||
| return NULL; | |||
| memset(tfb->map, 0xee, 8 * 4 * 3); | |||
| nouveau_bo_unmap(tfb); | |||
| BEGIN_RING(chan, RING_3D(TFB_ENABLE), 1); | |||
| OUT_RING (chan, 1); | |||
| BEGIN_RING(chan, RING_3D(TFB_BUFFER_ENABLE(0)), 5); | |||
| OUT_RING (chan, 1); | |||
| OUT_RELOCh(chan, tfb, 0, NOUVEAU_BO_GART | NOUVEAU_BO_WR); | |||
| OUT_RELOCl(chan, tfb, 0, NOUVEAU_BO_GART | NOUVEAU_BO_WR); | |||
| OUT_RING (chan, tfb->size); | |||
| OUT_RING (chan, 0); /* TFB_PRIMITIVE_ID(0) */ | |||
| BEGIN_RING(chan, RING_3D(TFB_UNK0700(0)), 3); | |||
| OUT_RING (chan, 0); | |||
| OUT_RING (chan, 8); /* TFB_VARYING_COUNT(0) */ | |||
| OUT_RING (chan, 32); /* TFB_BUFFER_STRIDE(0) */ | |||
| BEGIN_RING(chan, RING_3D(TFB_VARYING_LOCS(0)), 2); | |||
| OUT_RING (chan, 0x1f1e1d1c); | |||
| OUT_RING (chan, 0xa3a2a1a0); | |||
| for (i = 1; i < 4; ++i) { | |||
| BEGIN_RING(chan, RING_3D(TFB_BUFFER_ENABLE(i)), 1); | |||
| OUT_RING (chan, 0); | |||
| } | |||
| BEGIN_RING(chan, RING_3D(TFB_ENABLE), 1); | |||
| OUT_RING (chan, 1); | |||
| BEGIN_RING(chan, RING_3D_(0x135c), 1); | |||
| OUT_RING (chan, 1); | |||
| BEGIN_RING(chan, RING_3D_(0x135c), 1); | |||
| OUT_RING (chan, 0); | |||
| return tfb; | |||
| } | |||
| #endif | |||
| static void | |||
| nvc0_draw_arrays(struct nvc0_context *nvc0, | |||
| unsigned mode, unsigned start, unsigned count, | |||