Merge branch 'master' of git+ssh://joukj@git.freedesktop.org/git/mesa/mesa
[mesa.git] / src / mesa / drivers / dri / i915 / intel_regions.c
1 /**************************************************************************
2 *
3 * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28 /* Provide additional functionality on top of bufmgr buffers:
29 * - 2d semantics and blit operations
30 * - refcounting of buffers for multiple images in a buffer.
31 * - refcounting of buffer mappings.
32 * - some logic for moving the buffers to the best memory pools for
33 * given operations.
34 *
35 * Most of this is to make it easier to implement the fixed-layout
36 * mipmap tree required by intel hardware in the face of GL's
37 * programming interface where each image can be specifed in random
38 * order and it isn't clear what layout the tree should have until the
39 * last moment.
40 */
41
42 #include "intel_context.h"
43 #include "intel_regions.h"
44 #include "intel_blit.h"
45 #include "intel_buffer_objects.h"
46 #include "dri_bufmgr.h"
47 #include "intel_bufmgr_ttm.h"
48 #include "intel_batchbuffer.h"
49
50 #define FILE_DEBUG_FLAG DEBUG_REGION
51
52 void
53 intel_region_idle(intelScreenPrivate *intelScreen, struct intel_region *region)
54 {
55 DBG("%s\n", __FUNCTION__);
56 /* XXX: Using this function is likely bogus -- it ought to only have been
57 * used before a map, anyway, but leave this cheap implementation of it
58 * for now.
59 */
60 if (region && region->buffer) {
61 /* Mapping it for read will ensure that any acceleration to the region
62 * would have landed already.
63 */
64 dri_bo_map(region->buffer, GL_TRUE);
65 dri_bo_unmap(region->buffer);
66 }
67 }
68
69 /* XXX: Thread safety?
70 */
71 GLubyte *
72 intel_region_map(intelScreenPrivate *intelScreen, struct intel_region *region)
73 {
74 DBG("%s\n", __FUNCTION__);
75 if (!region->map_refcount++) {
76 if (region->pbo)
77 intel_region_cow(intelScreen, region);
78
79 dri_bo_map(region->buffer, GL_TRUE);
80 region->map = region->buffer->virtual;
81 }
82
83 return region->map;
84 }
85
86 void
87 intel_region_unmap(intelScreenPrivate *intelScreen, struct intel_region *region)
88 {
89 DBG("%s\n", __FUNCTION__);
90 if (!--region->map_refcount) {
91 dri_bo_unmap(region->buffer);
92 region->map = NULL;
93 }
94 }
95
96 struct intel_region *
97 intel_region_alloc(intelScreenPrivate *intelScreen,
98 GLuint cpp, GLuint pitch, GLuint height)
99 {
100 struct intel_region *region = calloc(sizeof(*region), 1);
101
102 DBG("%s\n", __FUNCTION__);
103
104 region->cpp = cpp;
105 region->pitch = pitch;
106 region->height = height; /* needed? */
107 region->refcount = 1;
108
109 region->buffer = dri_bo_alloc(intelScreen->bufmgr, "region",
110 pitch * cpp * height, 64, DRM_BO_FLAG_MEM_TT);
111 return region;
112 }
113
114 void
115 intel_region_reference(struct intel_region **dst, struct intel_region *src)
116 {
117 assert(*dst == NULL);
118 if (src) {
119 src->refcount++;
120 *dst = src;
121 }
122 }
123
124 void
125 intel_region_release(struct intel_region **region)
126 {
127 if (!*region)
128 return;
129
130 DBG("%s %d\n", __FUNCTION__, (*region)->refcount - 1);
131
132 ASSERT((*region)->refcount > 0);
133 (*region)->refcount--;
134
135 if ((*region)->refcount == 0) {
136 assert((*region)->map_refcount == 0);
137
138 if ((*region)->pbo)
139 (*region)->pbo->region = NULL;
140 (*region)->pbo = NULL;
141 dri_bo_unreference((*region)->buffer);
142 free(*region);
143 }
144 *region = NULL;
145 }
146
147
148 struct intel_region *
149 intel_region_create_static(intelScreenPrivate *intelScreen,
150 GLuint mem_type,
151 unsigned int bo_handle,
152 GLuint offset,
153 void *virtual,
154 GLuint cpp, GLuint pitch, GLuint height)
155 {
156 struct intel_region *region = calloc(sizeof(*region), 1);
157 DBG("%s\n", __FUNCTION__);
158
159 region->cpp = cpp;
160 region->pitch = pitch;
161 region->height = height; /* needed? */
162 region->refcount = 1;
163
164 if (intelScreen->ttm) {
165 assert(bo_handle != -1);
166 region->buffer = intel_ttm_bo_create_from_handle(intelScreen->bufmgr,
167 "static region",
168 bo_handle);
169 } else {
170 region->buffer = dri_bo_alloc_static(intelScreen->bufmgr,
171 "static region",
172 offset, pitch * cpp * height,
173 virtual,
174 DRM_BO_FLAG_MEM_TT);
175 }
176
177 return region;
178 }
179
180
181
182 void
183 intel_region_update_static(intelScreenPrivate *intelScreen,
184 struct intel_region *region,
185 GLuint mem_type,
186 unsigned int bo_handle,
187 GLuint offset,
188 void *virtual,
189 GLuint cpp, GLuint pitch, GLuint height)
190 {
191 DBG("%s\n", __FUNCTION__);
192
193 region->cpp = cpp;
194 region->pitch = pitch;
195 region->height = height; /* needed? */
196
197 /*
198 * We use a "shared" buffer type to indicate buffers created and
199 * shared by others.
200 */
201
202 dri_bo_unreference(region->buffer);
203 if (intelScreen->ttm) {
204 assert(bo_handle != -1);
205 region->buffer = intel_ttm_bo_create_from_handle(intelScreen->bufmgr,
206 "static region",
207 bo_handle);
208 } else {
209 region->buffer = dri_bo_alloc_static(intelScreen->bufmgr,
210 "static region",
211 offset, pitch * cpp * height,
212 virtual,
213 DRM_BO_FLAG_MEM_TT);
214 }
215 }
216
217
218
219 /*
220 * XXX Move this into core Mesa?
221 */
222 static void
223 _mesa_copy_rect(GLubyte * dst,
224 GLuint cpp,
225 GLuint dst_pitch,
226 GLuint dst_x,
227 GLuint dst_y,
228 GLuint width,
229 GLuint height,
230 const GLubyte * src,
231 GLuint src_pitch, GLuint src_x, GLuint src_y)
232 {
233 GLuint i;
234
235 dst_pitch *= cpp;
236 src_pitch *= cpp;
237 dst += dst_x * cpp;
238 src += src_x * cpp;
239 dst += dst_y * dst_pitch;
240 src += src_y * dst_pitch;
241 width *= cpp;
242
243 if (width == dst_pitch && width == src_pitch)
244 memcpy(dst, src, height * width);
245 else {
246 for (i = 0; i < height; i++) {
247 memcpy(dst, src, width);
248 dst += dst_pitch;
249 src += src_pitch;
250 }
251 }
252 }
253
254
255 /* Upload data to a rectangular sub-region. Lots of choices how to do this:
256 *
257 * - memcpy by span to current destination
258 * - upload data as new buffer and blit
259 *
260 * Currently always memcpy.
261 */
262 void
263 intel_region_data(intelScreenPrivate *intelScreen,
264 struct intel_region *dst,
265 GLuint dst_offset,
266 GLuint dstx, GLuint dsty,
267 const void *src, GLuint src_pitch,
268 GLuint srcx, GLuint srcy, GLuint width, GLuint height)
269 {
270 struct intel_context *intel = intelScreenContext(intelScreen);
271
272 DBG("%s\n", __FUNCTION__);
273
274 if (intel == NULL)
275 return;
276
277 if (dst->pbo) {
278 if (dstx == 0 &&
279 dsty == 0 && width == dst->pitch && height == dst->height)
280 intel_region_release_pbo(intelScreen, dst);
281 else
282 intel_region_cow(intelScreen, dst);
283 }
284
285
286 LOCK_HARDWARE(intel);
287
288 _mesa_copy_rect(intel_region_map(intelScreen, dst) + dst_offset,
289 dst->cpp,
290 dst->pitch,
291 dstx, dsty, width, height, src, src_pitch, srcx, srcy);
292
293 intel_region_unmap(intelScreen, dst);
294
295 UNLOCK_HARDWARE(intel);
296
297 }
298
299 /* Copy rectangular sub-regions. Need better logic about when to
300 * push buffers into AGP - will currently do so whenever possible.
301 */
302 void
303 intel_region_copy(intelScreenPrivate *intelScreen,
304 struct intel_region *dst,
305 GLuint dst_offset,
306 GLuint dstx, GLuint dsty,
307 struct intel_region *src,
308 GLuint src_offset,
309 GLuint srcx, GLuint srcy, GLuint width, GLuint height)
310 {
311 struct intel_context *intel = intelScreenContext(intelScreen);
312
313 DBG("%s\n", __FUNCTION__);
314
315 if (intel == NULL)
316 return;
317
318 if (dst->pbo) {
319 if (dstx == 0 &&
320 dsty == 0 && width == dst->pitch && height == dst->height)
321 intel_region_release_pbo(intelScreen, dst);
322 else
323 intel_region_cow(intelScreen, dst);
324 }
325
326 assert(src->cpp == dst->cpp);
327
328 intelEmitCopyBlit(intel,
329 dst->cpp,
330 src->pitch, src->buffer, src_offset,
331 dst->pitch, dst->buffer, dst_offset,
332 srcx, srcy, dstx, dsty, width, height,
333 GL_COPY);
334 }
335
336 /* Fill a rectangular sub-region. Need better logic about when to
337 * push buffers into AGP - will currently do so whenever possible.
338 */
339 void
340 intel_region_fill(intelScreenPrivate *intelScreen,
341 struct intel_region *dst,
342 GLuint dst_offset,
343 GLuint dstx, GLuint dsty,
344 GLuint width, GLuint height, GLuint color)
345 {
346 struct intel_context *intel = intelScreenContext(intelScreen);
347
348 DBG("%s\n", __FUNCTION__);
349
350 if (intel == NULL)
351 return;
352
353 if (dst->pbo) {
354 if (dstx == 0 &&
355 dsty == 0 && width == dst->pitch && height == dst->height)
356 intel_region_release_pbo(intelScreen, dst);
357 else
358 intel_region_cow(intelScreen, dst);
359 }
360
361 intelEmitFillBlit(intel,
362 dst->cpp,
363 dst->pitch, dst->buffer, dst_offset,
364 dstx, dsty, width, height, color);
365 }
366
367 /* Attach to a pbo, discarding our data. Effectively zero-copy upload
368 * the pbo's data.
369 */
370 void
371 intel_region_attach_pbo(intelScreenPrivate *intelScreen,
372 struct intel_region *region,
373 struct intel_buffer_object *pbo)
374 {
375 if (region->pbo == pbo)
376 return;
377
378 /* If there is already a pbo attached, break the cow tie now.
379 * Don't call intel_region_release_pbo() as that would
380 * unnecessarily allocate a new buffer we would have to immediately
381 * discard.
382 */
383 if (region->pbo) {
384 region->pbo->region = NULL;
385 region->pbo = NULL;
386 }
387
388 if (region->buffer) {
389 dri_bo_unreference(region->buffer);
390 region->buffer = NULL;
391 }
392
393 region->pbo = pbo;
394 region->pbo->region = region;
395 dri_bo_reference(pbo->buffer);
396 region->buffer = pbo->buffer;
397 }
398
399
400 /* Break the COW tie to the pbo and allocate a new buffer.
401 * The pbo gets to keep the data.
402 */
403 void
404 intel_region_release_pbo(intelScreenPrivate *intelScreen,
405 struct intel_region *region)
406 {
407 assert(region->buffer == region->pbo->buffer);
408 region->pbo->region = NULL;
409 region->pbo = NULL;
410 dri_bo_unreference(region->buffer);
411 region->buffer = NULL;
412
413 region->buffer = dri_bo_alloc(intelScreen->bufmgr, "region",
414 region->pitch * region->cpp * region->height,
415 64, DRM_BO_FLAG_MEM_TT);
416 }
417
418 /* Break the COW tie to the pbo. Both the pbo and the region end up
419 * with a copy of the data.
420 */
421 void
422 intel_region_cow(intelScreenPrivate *intelScreen, struct intel_region *region)
423 {
424 struct intel_context *intel = intelScreenContext(intelScreen);
425 struct intel_buffer_object *pbo = region->pbo;
426
427 if (intel == NULL)
428 return;
429
430 intel_region_release_pbo(intelScreen, region);
431
432 assert(region->cpp * region->pitch * region->height == pbo->Base.Size);
433
434 DBG("%s (%d bytes)\n", __FUNCTION__, pbo->Base.Size);
435
436 /* Now blit from the texture buffer to the new buffer:
437 */
438
439 intel_batchbuffer_flush(intel->batch);
440
441 if (!intel->locked) {
442 LOCK_HARDWARE(intel);
443 intelEmitCopyBlit(intel,
444 region->cpp,
445 region->pitch,
446 region->buffer, 0,
447 region->pitch,
448 pbo->buffer, 0,
449 0, 0, 0, 0,
450 region->pitch, region->height,
451 GL_COPY);
452
453 intel_batchbuffer_flush(intel->batch);
454 UNLOCK_HARDWARE(intel);
455 }
456 else {
457 intelEmitCopyBlit(intel,
458 region->cpp,
459 region->pitch,
460 region->buffer, 0,
461 region->pitch,
462 pbo->buffer, 0,
463 0, 0, 0, 0,
464 region->pitch, region->height,
465 GL_COPY);
466
467 intel_batchbuffer_flush(intel->batch);
468 }
469 }
470
471 dri_bo *
472 intel_region_buffer(intelScreenPrivate *intelScreen,
473 struct intel_region *region, GLuint flag)
474 {
475 if (region->pbo) {
476 if (flag == INTEL_WRITE_PART)
477 intel_region_cow(intelScreen, region);
478 else if (flag == INTEL_WRITE_FULL)
479 intel_region_release_pbo(intelScreen, region);
480 }
481
482 return region->buffer;
483 }