54b2d7af2eb184da080462b2e419bd735804f3d8
[mesa.git] / src / gallium / winsys / i915 / drm / i915_drm_batchbuffer.c
1
2 #include "i915_drm_winsys.h"
3 #include "util/u_memory.h"
4
5 #include "i915_drm.h"
6 #include "i915/i915_debug.h"
7 #include <xf86drm.h>
8 #include <stdio.h>
9
10 #define BATCH_RESERVED 16
11
12 #define INTEL_DEFAULT_RELOCS 100
13 #define INTEL_MAX_RELOCS 400
14
15 #define INTEL_BATCH_NO_CLIPRECTS 0x1
16 #define INTEL_BATCH_CLIPRECTS 0x2
17
18 #undef INTEL_RUN_SYNC
19
20 struct i915_drm_batchbuffer
21 {
22 struct i915_winsys_batchbuffer base;
23
24 size_t actual_size;
25
26 drm_intel_bo *bo;
27 };
28
29 static INLINE struct i915_drm_batchbuffer *
30 i915_drm_batchbuffer(struct i915_winsys_batchbuffer *batch)
31 {
32 return (struct i915_drm_batchbuffer *)batch;
33 }
34
35 static void
36 i915_drm_batchbuffer_reset(struct i915_drm_batchbuffer *batch)
37 {
38 struct i915_drm_winsys *idws = i915_drm_winsys(batch->base.iws);
39
40 if (batch->bo)
41 drm_intel_bo_unreference(batch->bo);
42 batch->bo = drm_intel_bo_alloc(idws->gem_manager,
43 "gallium3d_batchbuffer",
44 batch->actual_size,
45 4096);
46
47 memset(batch->base.map, 0, batch->actual_size);
48 batch->base.ptr = batch->base.map;
49 batch->base.size = batch->actual_size - BATCH_RESERVED;
50 batch->base.relocs = 0;
51 }
52
53 static struct i915_winsys_batchbuffer *
54 i915_drm_batchbuffer_create(struct i915_winsys *iws)
55 {
56 struct i915_drm_winsys *idws = i915_drm_winsys(iws);
57 struct i915_drm_batchbuffer *batch = CALLOC_STRUCT(i915_drm_batchbuffer);
58
59 batch->actual_size = idws->max_batch_size;
60
61 batch->base.map = MALLOC(batch->actual_size);
62 batch->base.ptr = NULL;
63 batch->base.size = 0;
64
65 batch->base.relocs = 0;
66 batch->base.max_relocs = 300;/*INTEL_DEFAULT_RELOCS;*/
67
68 batch->base.iws = iws;
69
70 i915_drm_batchbuffer_reset(batch);
71
72 return &batch->base;
73 }
74
75 static int
76 i915_drm_batchbuffer_reloc(struct i915_winsys_batchbuffer *ibatch,
77 struct i915_winsys_buffer *buffer,
78 enum i915_winsys_buffer_usage usage,
79 unsigned pre_add, boolean fenced)
80 {
81 struct i915_drm_batchbuffer *batch = i915_drm_batchbuffer(ibatch);
82 unsigned write_domain = 0;
83 unsigned read_domain = 0;
84 unsigned offset;
85 int ret = 0;
86
87 assert(batch->base.relocs < batch->base.max_relocs);
88
89 switch (usage) {
90 case I915_USAGE_SAMPLER:
91 write_domain = 0;
92 read_domain = I915_GEM_DOMAIN_SAMPLER;
93 break;
94 case I915_USAGE_RENDER:
95 write_domain = I915_GEM_DOMAIN_RENDER;
96 read_domain = I915_GEM_DOMAIN_RENDER;
97 break;
98 case I915_USAGE_2D_TARGET:
99 write_domain = I915_GEM_DOMAIN_RENDER;
100 read_domain = I915_GEM_DOMAIN_RENDER;
101 break;
102 case I915_USAGE_2D_SOURCE:
103 write_domain = 0;
104 read_domain = I915_GEM_DOMAIN_RENDER;
105 break;
106 case I915_USAGE_VERTEX:
107 write_domain = 0;
108 read_domain = I915_GEM_DOMAIN_VERTEX;
109 break;
110 default:
111 assert(0);
112 return -1;
113 }
114
115 offset = (unsigned)(batch->base.ptr - batch->base.map);
116
117 if (fenced)
118 ret = drm_intel_bo_emit_reloc_fence(batch->bo, offset,
119 intel_bo(buffer), pre_add,
120 read_domain,
121 write_domain);
122 else
123 ret = drm_intel_bo_emit_reloc(batch->bo, offset,
124 intel_bo(buffer), pre_add,
125 read_domain,
126 write_domain);
127
128 ((uint32_t*)batch->base.ptr)[0] = intel_bo(buffer)->offset + pre_add;
129 batch->base.ptr += 4;
130
131 if (!ret)
132 batch->base.relocs++;
133
134 return ret;
135 }
136
137 static void
138 i915_drm_throttle(struct i915_drm_winsys *idws)
139 {
140 drmIoctl(idws->fd, DRM_IOCTL_I915_GEM_THROTTLE, NULL);
141 }
142
143 static void
144 i915_drm_batchbuffer_flush(struct i915_winsys_batchbuffer *ibatch,
145 struct pipe_fence_handle **fence)
146 {
147 struct i915_drm_batchbuffer *batch = i915_drm_batchbuffer(ibatch);
148 unsigned used;
149 int ret;
150
151 /* MI_BATCH_BUFFER_END */
152 i915_winsys_batchbuffer_dword_unchecked(ibatch, (0xA<<23));
153
154 used = batch->base.ptr - batch->base.map;
155 if (used & 4) {
156 /* MI_NOOP */
157 i915_winsys_batchbuffer_dword_unchecked(ibatch, 0);
158 used += 4;
159 }
160
161 /* Do the sending to HW */
162 ret = drm_intel_bo_subdata(batch->bo, 0, used, batch->base.map);
163 if (ret == 0 && i915_drm_winsys(ibatch->iws)->send_cmd)
164 ret = drm_intel_bo_exec(batch->bo, used, NULL, 0, 0);
165
166 i915_drm_throttle(i915_drm_winsys(ibatch->iws));
167
168 if (ret != 0 || i915_drm_winsys(ibatch->iws)->dump_cmd) {
169 i915_dump_batchbuffer(ibatch);
170 assert(ret == 0);
171 }
172
173 if (i915_drm_winsys(ibatch->iws)->dump_raw_file) {
174 FILE *file = fopen(i915_drm_winsys(ibatch->iws)->dump_raw_file, "a");
175 if (file) {
176 fwrite(batch->base.map, used, 1, file);
177 fclose(file);
178 }
179 }
180
181 #ifdef INTEL_RUN_SYNC
182 drm_intel_bo_wait_rendering(batch->bo);
183 #endif
184
185 if (fence) {
186 ibatch->iws->fence_reference(ibatch->iws, fence, NULL);
187
188 #ifdef INTEL_RUN_SYNC
189 /* we run synced to GPU so just pass null */
190 (*fence) = i915_drm_fence_create(NULL);
191 #else
192 (*fence) = i915_drm_fence_create(batch->bo);
193 #endif
194 }
195
196 i915_drm_batchbuffer_reset(batch);
197 }
198
199 static void
200 i915_drm_batchbuffer_destroy(struct i915_winsys_batchbuffer *ibatch)
201 {
202 struct i915_drm_batchbuffer *batch = i915_drm_batchbuffer(ibatch);
203
204 if (batch->bo)
205 drm_intel_bo_unreference(batch->bo);
206
207 FREE(batch->base.map);
208 FREE(batch);
209 }
210
211 void i915_drm_winsys_init_batchbuffer_functions(struct i915_drm_winsys *idws)
212 {
213 idws->base.batchbuffer_create = i915_drm_batchbuffer_create;
214 idws->base.batchbuffer_reloc = i915_drm_batchbuffer_reloc;
215 idws->base.batchbuffer_flush = i915_drm_batchbuffer_flush;
216 idws->base.batchbuffer_destroy = i915_drm_batchbuffer_destroy;
217 }