cb0f4ba083b0c1ad0ee20a642d861b0724d69e5e
[mesa.git] / src / mesa / drivers / dri / intel / 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 <sys/ioctl.h>
43 #include <errno.h>
44
45 #include "intel_context.h"
46 #include "intel_regions.h"
47 #include "intel_blit.h"
48 #include "intel_buffer_objects.h"
49 #include "intel_bufmgr.h"
50 #include "intel_batchbuffer.h"
51 #include "intel_chipset.h"
52
53 #define FILE_DEBUG_FLAG DEBUG_REGION
54
55 /* XXX: Thread safety?
56 */
57 GLubyte *
58 intel_region_map(struct intel_context *intel, struct intel_region *region)
59 {
60 DBG("%s\n", __FUNCTION__);
61 if (!region->map_refcount++) {
62 if (region->pbo)
63 intel_region_cow(intel, region);
64
65 dri_bo_map(region->buffer, GL_TRUE);
66 region->map = region->buffer->virtual;
67 }
68
69 return region->map;
70 }
71
72 void
73 intel_region_unmap(struct intel_context *intel, struct intel_region *region)
74 {
75 DBG("%s\n", __FUNCTION__);
76 if (!--region->map_refcount) {
77 dri_bo_unmap(region->buffer);
78 region->map = NULL;
79 }
80 }
81
82 static int
83 intel_set_region_tiling_gem(struct intel_context *intel,
84 struct intel_region *region,
85 uint32_t bo_handle)
86 {
87 struct drm_i915_gem_get_tiling get_tiling;
88 int ret;
89
90 memset(&get_tiling, 0, sizeof(get_tiling));
91
92 get_tiling.handle = bo_handle;
93 ret = ioctl(intel->driFd, DRM_IOCTL_I915_GEM_GET_TILING, &get_tiling);
94 if (ret != 0) {
95 fprintf(stderr, "Failed to get tiling state for region: %s\n",
96 strerror(errno));
97 return ret;
98 }
99
100 region->tiling = get_tiling.tiling_mode;
101 region->bit_6_swizzle = get_tiling.swizzle_mode;
102
103 return 0;
104 }
105
106 static struct intel_region *
107 intel_region_alloc_internal(struct intel_context *intel,
108 GLuint cpp,
109 GLuint width, GLuint height, GLuint pitch,
110 dri_bo *buffer)
111 {
112 struct intel_region *region;
113
114 DBG("%s\n", __FUNCTION__);
115
116 if (buffer == NULL)
117 return NULL;
118
119 region = calloc(sizeof(*region), 1);
120 region->cpp = cpp;
121 region->width = width;
122 region->height = height;
123 region->pitch = pitch;
124 region->refcount = 1;
125 region->buffer = buffer;
126
127 /* Default to no tiling */
128 region->tiling = I915_TILING_NONE;
129 region->bit_6_swizzle = I915_BIT_6_SWIZZLE_NONE;
130
131 return region;
132 }
133
134 struct intel_region *
135 intel_region_alloc(struct intel_context *intel,
136 GLuint cpp, GLuint width, GLuint height, GLuint pitch)
137 {
138 dri_bo *buffer;
139
140 buffer = dri_bo_alloc(intel->bufmgr, "region",
141 pitch * cpp * height, 64);
142
143 return intel_region_alloc_internal(intel, cpp, width, height, pitch, buffer);
144 }
145
146 struct intel_region *
147 intel_region_alloc_for_handle(struct intel_context *intel,
148 GLuint cpp,
149 GLuint width, GLuint height, GLuint pitch,
150 GLuint handle, const char *name)
151 {
152 struct intel_region *region;
153 dri_bo *buffer;
154
155 buffer = intel_bo_gem_create_from_name(intel->bufmgr, name, handle);
156
157 region = intel_region_alloc_internal(intel, cpp,
158 width, height, pitch, buffer);
159 if (region == NULL)
160 return region;
161
162 intel_set_region_tiling_gem(intel, region, handle);
163
164 return region;
165 }
166
167 void
168 intel_region_reference(struct intel_region **dst, struct intel_region *src)
169 {
170 if (src)
171 DBG("%s %d\n", __FUNCTION__, src->refcount);
172
173 assert(*dst == NULL);
174 if (src) {
175 src->refcount++;
176 *dst = src;
177 }
178 }
179
180 void
181 intel_region_release(struct intel_region **region_handle)
182 {
183 struct intel_region *region = *region_handle;
184
185 if (region == NULL)
186 return;
187
188 DBG("%s %d\n", __FUNCTION__, region->refcount - 1);
189
190 ASSERT(region->refcount > 0);
191 region->refcount--;
192
193 if (region->refcount == 0) {
194 assert(region->map_refcount == 0);
195
196 if (region->pbo)
197 region->pbo->region = NULL;
198 region->pbo = NULL;
199 dri_bo_unreference(region->buffer);
200
201 if (region->classic_map != NULL) {
202 drmUnmap(region->classic_map,
203 region->pitch * region->cpp * region->height);
204 }
205
206 free(region);
207 }
208 *region_handle = NULL;
209 }
210
211 /*
212 * XXX Move this into core Mesa?
213 */
214 void
215 _mesa_copy_rect(GLubyte * dst,
216 GLuint cpp,
217 GLuint dst_pitch,
218 GLuint dst_x,
219 GLuint dst_y,
220 GLuint width,
221 GLuint height,
222 const GLubyte * src,
223 GLuint src_pitch, GLuint src_x, GLuint src_y)
224 {
225 GLuint i;
226
227 dst_pitch *= cpp;
228 src_pitch *= cpp;
229 dst += dst_x * cpp;
230 src += src_x * cpp;
231 dst += dst_y * dst_pitch;
232 src += src_y * dst_pitch;
233 width *= cpp;
234
235 if (width == dst_pitch && width == src_pitch)
236 memcpy(dst, src, height * width);
237 else {
238 for (i = 0; i < height; i++) {
239 memcpy(dst, src, width);
240 dst += dst_pitch;
241 src += src_pitch;
242 }
243 }
244 }
245
246
247 /* Upload data to a rectangular sub-region. Lots of choices how to do this:
248 *
249 * - memcpy by span to current destination
250 * - upload data as new buffer and blit
251 *
252 * Currently always memcpy.
253 */
254 void
255 intel_region_data(struct intel_context *intel,
256 struct intel_region *dst,
257 GLuint dst_offset,
258 GLuint dstx, GLuint dsty,
259 const void *src, GLuint src_pitch,
260 GLuint srcx, GLuint srcy, GLuint width, GLuint height)
261 {
262 GLboolean locked = GL_FALSE;
263
264 DBG("%s\n", __FUNCTION__);
265
266 if (intel == NULL)
267 return;
268
269 if (dst->pbo) {
270 if (dstx == 0 &&
271 dsty == 0 && width == dst->pitch && height == dst->height)
272 intel_region_release_pbo(intel, dst);
273 else
274 intel_region_cow(intel, dst);
275 }
276
277 if (!intel->locked) {
278 LOCK_HARDWARE(intel);
279 locked = GL_TRUE;
280 }
281
282 _mesa_copy_rect(intel_region_map(intel, dst) + dst_offset,
283 dst->cpp,
284 dst->pitch,
285 dstx, dsty, width, height, src, src_pitch, srcx, srcy);
286
287 intel_region_unmap(intel, dst);
288
289 if (locked)
290 UNLOCK_HARDWARE(intel);
291
292 }
293
294 /* Copy rectangular sub-regions. Need better logic about when to
295 * push buffers into AGP - will currently do so whenever possible.
296 */
297 void
298 intel_region_copy(struct intel_context *intel,
299 struct intel_region *dst,
300 GLuint dst_offset,
301 GLuint dstx, GLuint dsty,
302 struct intel_region *src,
303 GLuint src_offset,
304 GLuint srcx, GLuint srcy, GLuint width, GLuint height)
305 {
306 DBG("%s\n", __FUNCTION__);
307
308 if (intel == NULL)
309 return;
310
311 if (dst->pbo) {
312 if (dstx == 0 &&
313 dsty == 0 && width == dst->pitch && height == dst->height)
314 intel_region_release_pbo(intel, dst);
315 else
316 intel_region_cow(intel, dst);
317 }
318
319 assert(src->cpp == dst->cpp);
320
321 intelEmitCopyBlit(intel,
322 dst->cpp,
323 src->pitch, src->buffer, src_offset, src->tiling,
324 dst->pitch, dst->buffer, dst_offset, dst->tiling,
325 srcx, srcy, dstx, dsty, width, height,
326 GL_COPY);
327 }
328
329 /* Fill a rectangular sub-region. Need better logic about when to
330 * push buffers into AGP - will currently do so whenever possible.
331 */
332 void
333 intel_region_fill(struct intel_context *intel,
334 struct intel_region *dst,
335 GLuint dst_offset,
336 GLuint dstx, GLuint dsty,
337 GLuint width, GLuint height, GLuint color)
338 {
339 DBG("%s\n", __FUNCTION__);
340
341 if (intel == NULL)
342 return;
343
344 if (dst->pbo) {
345 if (dstx == 0 &&
346 dsty == 0 && width == dst->pitch && height == dst->height)
347 intel_region_release_pbo(intel, dst);
348 else
349 intel_region_cow(intel, dst);
350 }
351
352 intelEmitFillBlit(intel,
353 dst->cpp,
354 dst->pitch, dst->buffer, dst_offset, dst->tiling,
355 dstx, dsty, width, height, color);
356 }
357
358 /* Attach to a pbo, discarding our data. Effectively zero-copy upload
359 * the pbo's data.
360 */
361 void
362 intel_region_attach_pbo(struct intel_context *intel,
363 struct intel_region *region,
364 struct intel_buffer_object *pbo)
365 {
366 if (region->pbo == pbo)
367 return;
368
369 /* If there is already a pbo attached, break the cow tie now.
370 * Don't call intel_region_release_pbo() as that would
371 * unnecessarily allocate a new buffer we would have to immediately
372 * discard.
373 */
374 if (region->pbo) {
375 region->pbo->region = NULL;
376 region->pbo = NULL;
377 }
378
379 if (region->buffer) {
380 dri_bo_unreference(region->buffer);
381 region->buffer = NULL;
382 }
383
384 region->pbo = pbo;
385 region->pbo->region = region;
386 dri_bo_reference(pbo->buffer);
387 region->buffer = pbo->buffer;
388 }
389
390
391 /* Break the COW tie to the pbo and allocate a new buffer.
392 * The pbo gets to keep the data.
393 */
394 void
395 intel_region_release_pbo(struct intel_context *intel,
396 struct intel_region *region)
397 {
398 assert(region->buffer == region->pbo->buffer);
399 region->pbo->region = NULL;
400 region->pbo = NULL;
401 dri_bo_unreference(region->buffer);
402 region->buffer = NULL;
403
404 region->buffer = dri_bo_alloc(intel->bufmgr, "region",
405 region->pitch * region->cpp * region->height,
406 64);
407 }
408
409 /* Break the COW tie to the pbo. Both the pbo and the region end up
410 * with a copy of the data.
411 */
412 void
413 intel_region_cow(struct intel_context *intel, struct intel_region *region)
414 {
415 struct intel_buffer_object *pbo = region->pbo;
416 GLboolean was_locked = intel->locked;
417
418 if (intel == NULL)
419 return;
420
421 intel_region_release_pbo(intel, region);
422
423 assert(region->cpp * region->pitch * region->height == pbo->Base.Size);
424
425 DBG("%s (%d bytes)\n", __FUNCTION__, pbo->Base.Size);
426
427 /* Now blit from the texture buffer to the new buffer:
428 */
429
430 was_locked = intel->locked;
431 if (!was_locked)
432 LOCK_HARDWARE(intel);
433
434 intelEmitCopyBlit(intel,
435 region->cpp,
436 region->pitch, region->buffer, 0, region->tiling,
437 region->pitch, pbo->buffer, 0, region->tiling,
438 0, 0, 0, 0,
439 region->pitch, region->height,
440 GL_COPY);
441
442 if (!was_locked)
443 UNLOCK_HARDWARE(intel);
444 }
445
446 dri_bo *
447 intel_region_buffer(struct intel_context *intel,
448 struct intel_region *region, GLuint flag)
449 {
450 if (region->pbo) {
451 if (flag == INTEL_WRITE_PART)
452 intel_region_cow(intel, region);
453 else if (flag == INTEL_WRITE_FULL)
454 intel_region_release_pbo(intel, region);
455 }
456
457 return region->buffer;
458 }
459
460 static struct intel_region *
461 intel_recreate_static(struct intel_context *intel,
462 const char *name,
463 struct intel_region *region,
464 intelRegion *region_desc)
465 {
466 intelScreenPrivate *intelScreen = intel->intelScreen;
467 int ret;
468
469 if (region == NULL) {
470 region = calloc(sizeof(*region), 1);
471 region->refcount = 1;
472 }
473
474 if (intel->ctx.Visual.rgbBits == 24)
475 region->cpp = 4;
476 else
477 region->cpp = intel->ctx.Visual.rgbBits / 8;
478 region->pitch = intelScreen->pitch;
479 region->height = intelScreen->height; /* needed? */
480
481 if (intel->ttm) {
482 assert(region_desc->bo_handle != -1);
483 region->buffer = intel_bo_gem_create_from_name(intel->bufmgr,
484 name,
485 region_desc->bo_handle);
486
487 intel_set_region_tiling_gem(intel, region, region_desc->bo_handle);
488 } else {
489 ret = drmMap(intel->driFd, region_desc->handle,
490 region->pitch * region->cpp * region->height,
491 &region->classic_map);
492 if (ret != 0) {
493 fprintf(stderr, "Failed to drmMap %s buffer\n", name);
494 free(region);
495 return NULL;
496 }
497
498 region->buffer = intel_bo_fake_alloc_static(intel->bufmgr,
499 name,
500 region_desc->offset,
501 region->pitch * region->cpp *
502 region->height,
503 region->classic_map);
504
505 /* The sarea just gives us a boolean for whether it's tiled or not,
506 * instead of which tiling mode it is. Guess.
507 */
508 if (region_desc->tiled) {
509 if (IS_965(intel->intelScreen->deviceID) &&
510 region_desc == &intelScreen->depth)
511 region->tiling = I915_TILING_Y;
512 else
513 region->tiling = I915_TILING_X;
514 } else {
515 region->tiling = I915_TILING_NONE;
516 }
517
518 region->bit_6_swizzle = I915_BIT_6_SWIZZLE_NONE;
519 }
520
521 assert(region->buffer != NULL);
522
523 return region;
524 }
525
526 /**
527 * Create intel_region structs to describe the static front, back, and depth
528 * buffers created by the xserver.
529 *
530 * Although FBO's mean we now no longer use these as render targets in
531 * all circumstances, they won't go away until the back and depth
532 * buffers become private, and the front buffer will remain even then.
533 *
534 * Note that these don't allocate video memory, just describe
535 * allocations alread made by the X server.
536 */
537 void
538 intel_recreate_static_regions(struct intel_context *intel)
539 {
540 intelScreenPrivate *intelScreen = intel->intelScreen;
541
542 intel->front_region =
543 intel_recreate_static(intel, "front",
544 intel->front_region,
545 &intelScreen->front);
546
547 intel->back_region =
548 intel_recreate_static(intel, "back",
549 intel->back_region,
550 &intelScreen->back);
551
552 #ifdef I915
553 if (intelScreen->third.handle) {
554 intel->third_region =
555 intel_recreate_static(intel, "third",
556 intel->third_region,
557 &intelScreen->third);
558 }
559 #endif /* I915 */
560
561 /* Still assumes front.cpp == depth.cpp. We can kill this when we move to
562 * private buffers.
563 */
564 intel->depth_region =
565 intel_recreate_static(intel, "depth",
566 intel->depth_region,
567 &intelScreen->depth);
568 }