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
20struct i915_drm_batchbuffer
21{
22   struct i915_winsys_batchbuffer base;
23
24   size_t actual_size;
25
26   drm_intel_bo *bo;
27};
28
29static INLINE struct i915_drm_batchbuffer *
30i915_drm_batchbuffer(struct i915_winsys_batchbuffer *batch)
31{
32   return (struct i915_drm_batchbuffer *)batch;
33}
34
35static void
36i915_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
53static struct i915_winsys_batchbuffer *
54i915_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
67   batch->base.iws = iws;
68
69   i915_drm_batchbuffer_reset(batch);
70
71   return &batch->base;
72}
73
74static boolean
75i915_drm_batchbuffer_validate_buffers(struct i915_winsys_batchbuffer *batch,
76				      struct i915_winsys_buffer **buffer,
77				      int num_of_buffers)
78{
79   struct i915_drm_batchbuffer *drm_batch = i915_drm_batchbuffer(batch);
80   drm_intel_bo *bos[num_of_buffers + 1];
81   int i, ret;
82
83   bos[0] = drm_batch->bo;
84   for (i = 0; i < num_of_buffers; i++)
85      bos[i+1] = intel_bo(buffer[i]);
86
87   ret = drm_intel_bufmgr_check_aperture_space(bos, num_of_buffers);
88   if (ret != 0)
89      return FALSE;
90
91   return TRUE;
92}
93
94static int
95i915_drm_batchbuffer_reloc(struct i915_winsys_batchbuffer *ibatch,
96                            struct i915_winsys_buffer *buffer,
97                            enum i915_winsys_buffer_usage usage,
98                            unsigned pre_add, boolean fenced)
99{
100   struct i915_drm_batchbuffer *batch = i915_drm_batchbuffer(ibatch);
101   unsigned write_domain = 0;
102   unsigned read_domain = 0;
103   unsigned offset;
104   int ret = 0;
105
106   switch (usage) {
107   case I915_USAGE_SAMPLER:
108      write_domain = 0;
109      read_domain = I915_GEM_DOMAIN_SAMPLER;
110      break;
111   case I915_USAGE_RENDER:
112      write_domain = I915_GEM_DOMAIN_RENDER;
113      read_domain = I915_GEM_DOMAIN_RENDER;
114      break;
115   case I915_USAGE_2D_TARGET:
116      write_domain = I915_GEM_DOMAIN_RENDER;
117      read_domain = I915_GEM_DOMAIN_RENDER;
118      break;
119   case I915_USAGE_2D_SOURCE:
120      write_domain = 0;
121      read_domain = I915_GEM_DOMAIN_RENDER;
122      break;
123   case I915_USAGE_VERTEX:
124      write_domain = 0;
125      read_domain = I915_GEM_DOMAIN_VERTEX;
126      break;
127   default:
128      assert(0);
129      return -1;
130   }
131
132   offset = (unsigned)(batch->base.ptr - batch->base.map);
133
134   if (fenced)
135      ret = drm_intel_bo_emit_reloc_fence(batch->bo, offset,
136				    intel_bo(buffer), pre_add,
137				    read_domain,
138				    write_domain);
139   else
140      ret = drm_intel_bo_emit_reloc(batch->bo, offset,
141				    intel_bo(buffer), pre_add,
142				    read_domain,
143				    write_domain);
144
145   ((uint32_t*)batch->base.ptr)[0] = intel_bo(buffer)->offset + pre_add;
146   batch->base.ptr += 4;
147
148   if (!ret)
149      batch->base.relocs++;
150
151   return ret;
152}
153
154static void
155i915_drm_throttle(struct i915_drm_winsys *idws)
156{
157   drmIoctl(idws->fd, DRM_IOCTL_I915_GEM_THROTTLE, NULL);
158}
159
160static void
161i915_drm_batchbuffer_flush(struct i915_winsys_batchbuffer *ibatch,
162                            struct pipe_fence_handle **fence)
163{
164   struct i915_drm_batchbuffer *batch = i915_drm_batchbuffer(ibatch);
165   unsigned used;
166   int ret;
167
168   /* MI_BATCH_BUFFER_END */
169   i915_winsys_batchbuffer_dword_unchecked(ibatch, (0xA<<23));
170
171   used = batch->base.ptr - batch->base.map;
172   if (used & 4) {
173      /* MI_NOOP */
174      i915_winsys_batchbuffer_dword_unchecked(ibatch, 0);
175      used += 4;
176   }
177
178   /* Do the sending to HW */
179   ret = drm_intel_bo_subdata(batch->bo, 0, used, batch->base.map);
180   if (ret == 0 && i915_drm_winsys(ibatch->iws)->send_cmd)
181      ret = drm_intel_bo_exec(batch->bo, used, NULL, 0, 0);
182
183   i915_drm_throttle(i915_drm_winsys(ibatch->iws));
184
185   if (ret != 0 || i915_drm_winsys(ibatch->iws)->dump_cmd) {
186      i915_dump_batchbuffer(ibatch);
187      assert(ret == 0);
188   }
189
190   if (i915_drm_winsys(ibatch->iws)->dump_raw_file) {
191      FILE *file = fopen(i915_drm_winsys(ibatch->iws)->dump_raw_file, "a");
192      if (file) {
193	 fwrite(batch->base.map, used, 1, file);
194	 fclose(file);
195      }
196   }
197
198#ifdef INTEL_RUN_SYNC
199   drm_intel_bo_wait_rendering(batch->bo);
200#endif
201
202   if (fence) {
203      ibatch->iws->fence_reference(ibatch->iws, fence, NULL);
204
205#ifdef INTEL_RUN_SYNC
206      /* we run synced to GPU so just pass null */
207      (*fence) = i915_drm_fence_create(NULL);
208#else
209      (*fence) = i915_drm_fence_create(batch->bo);
210#endif
211   }
212
213   i915_drm_batchbuffer_reset(batch);
214}
215
216static void
217i915_drm_batchbuffer_destroy(struct i915_winsys_batchbuffer *ibatch)
218{
219   struct i915_drm_batchbuffer *batch = i915_drm_batchbuffer(ibatch);
220
221   if (batch->bo)
222      drm_intel_bo_unreference(batch->bo);
223
224   FREE(batch->base.map);
225   FREE(batch);
226}
227
228void i915_drm_winsys_init_batchbuffer_functions(struct i915_drm_winsys *idws)
229{
230   idws->base.batchbuffer_create = i915_drm_batchbuffer_create;
231   idws->base.validate_buffers = i915_drm_batchbuffer_validate_buffers;
232   idws->base.batchbuffer_reloc = i915_drm_batchbuffer_reloc;
233   idws->base.batchbuffer_flush = i915_drm_batchbuffer_flush;
234   idws->base.batchbuffer_destroy = i915_drm_batchbuffer_destroy;
235}
236