a47b2880907ee3494291c0ecd775d940a86e95c1
[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 "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(struct intel_context *intel, 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(struct intel_context *intel, struct intel_region *region)
73 {
74 DBG("%s\n", __FUNCTION__);
75 if (!region->map_refcount++) {
76 if (region->pbo)
77 intel_region_cow(intel, 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(struct intel_context *intel, 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(struct intel_context *intel,
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(intel->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 * XXX Move this into core Mesa?
149 */
150 static void
151 _mesa_copy_rect(GLubyte * dst,
152 GLuint cpp,
153 GLuint dst_pitch,
154 GLuint dst_x,
155 GLuint dst_y,
156 GLuint width,
157 GLuint height,
158 const GLubyte * src,
159 GLuint src_pitch, GLuint src_x, GLuint src_y)
160 {
161 GLuint i;
162
163 dst_pitch *= cpp;
164 src_pitch *= cpp;
165 dst += dst_x * cpp;
166 src += src_x * cpp;
167 dst += dst_y * dst_pitch;
168 src += src_y * dst_pitch;
169 width *= cpp;
170
171 if (width == dst_pitch && width == src_pitch)
172 memcpy(dst, src, height * width);
173 else {
174 for (i = 0; i < height; i++) {
175 memcpy(dst, src, width);
176 dst += dst_pitch;
177 src += src_pitch;
178 }
179 }
180 }
181
182
183 /* Upload data to a rectangular sub-region. Lots of choices how to do this:
184 *
185 * - memcpy by span to current destination
186 * - upload data as new buffer and blit
187 *
188 * Currently always memcpy.
189 */
190 void
191 intel_region_data(struct intel_context *intel,
192 struct intel_region *dst,
193 GLuint dst_offset,
194 GLuint dstx, GLuint dsty,
195 const void *src, GLuint src_pitch,
196 GLuint srcx, GLuint srcy, GLuint width, GLuint height)
197 {
198 DBG("%s\n", __FUNCTION__);
199
200 if (intel == NULL)
201 return;
202
203 if (dst->pbo) {
204 if (dstx == 0 &&
205 dsty == 0 && width == dst->pitch && height == dst->height)
206 intel_region_release_pbo(intel, dst);
207 else
208 intel_region_cow(intel, dst);
209 }
210
211
212 LOCK_HARDWARE(intel);
213
214 _mesa_copy_rect(intel_region_map(intel, dst) + dst_offset,
215 dst->cpp,
216 dst->pitch,
217 dstx, dsty, width, height, src, src_pitch, srcx, srcy);
218
219 intel_region_unmap(intel, dst);
220
221 UNLOCK_HARDWARE(intel);
222
223 }
224
225 /* Copy rectangular sub-regions. Need better logic about when to
226 * push buffers into AGP - will currently do so whenever possible.
227 */
228 void
229 intel_region_copy(struct intel_context *intel,
230 struct intel_region *dst,
231 GLuint dst_offset,
232 GLuint dstx, GLuint dsty,
233 struct intel_region *src,
234 GLuint src_offset,
235 GLuint srcx, GLuint srcy, GLuint width, GLuint height)
236 {
237 DBG("%s\n", __FUNCTION__);
238
239 if (intel == NULL)
240 return;
241
242 if (dst->pbo) {
243 if (dstx == 0 &&
244 dsty == 0 && width == dst->pitch && height == dst->height)
245 intel_region_release_pbo(intel, dst);
246 else
247 intel_region_cow(intel, dst);
248 }
249
250 assert(src->cpp == dst->cpp);
251
252 intelEmitCopyBlit(intel,
253 dst->cpp,
254 src->pitch, src->buffer, src_offset, src->tiled,
255 dst->pitch, dst->buffer, dst_offset, dst->tiled,
256 srcx, srcy, dstx, dsty, width, height,
257 GL_COPY);
258 }
259
260 /* Fill a rectangular sub-region. Need better logic about when to
261 * push buffers into AGP - will currently do so whenever possible.
262 */
263 void
264 intel_region_fill(struct intel_context *intel,
265 struct intel_region *dst,
266 GLuint dst_offset,
267 GLuint dstx, GLuint dsty,
268 GLuint width, GLuint height, GLuint color)
269 {
270 DBG("%s\n", __FUNCTION__);
271
272 if (intel == NULL)
273 return;
274
275 if (dst->pbo) {
276 if (dstx == 0 &&
277 dsty == 0 && width == dst->pitch && height == dst->height)
278 intel_region_release_pbo(intel, dst);
279 else
280 intel_region_cow(intel, dst);
281 }
282
283 intelEmitFillBlit(intel,
284 dst->cpp,
285 dst->pitch, dst->buffer, dst_offset, dst->tiled,
286 dstx, dsty, width, height, color);
287 }
288
289 /* Attach to a pbo, discarding our data. Effectively zero-copy upload
290 * the pbo's data.
291 */
292 void
293 intel_region_attach_pbo(struct intel_context *intel,
294 struct intel_region *region,
295 struct intel_buffer_object *pbo)
296 {
297 if (region->pbo == pbo)
298 return;
299
300 /* If there is already a pbo attached, break the cow tie now.
301 * Don't call intel_region_release_pbo() as that would
302 * unnecessarily allocate a new buffer we would have to immediately
303 * discard.
304 */
305 if (region->pbo) {
306 region->pbo->region = NULL;
307 region->pbo = NULL;
308 }
309
310 if (region->buffer) {
311 dri_bo_unreference(region->buffer);
312 region->buffer = NULL;
313 }
314
315 region->pbo = pbo;
316 region->pbo->region = region;
317 dri_bo_reference(pbo->buffer);
318 region->buffer = pbo->buffer;
319 }
320
321
322 /* Break the COW tie to the pbo and allocate a new buffer.
323 * The pbo gets to keep the data.
324 */
325 void
326 intel_region_release_pbo(struct intel_context *intel,
327 struct intel_region *region)
328 {
329 assert(region->buffer == region->pbo->buffer);
330 region->pbo->region = NULL;
331 region->pbo = NULL;
332 dri_bo_unreference(region->buffer);
333 region->buffer = NULL;
334
335 region->buffer = dri_bo_alloc(intel->bufmgr, "region",
336 region->pitch * region->cpp * region->height,
337 64, DRM_BO_FLAG_MEM_TT);
338 }
339
340 /* Break the COW tie to the pbo. Both the pbo and the region end up
341 * with a copy of the data.
342 */
343 void
344 intel_region_cow(struct intel_context *intel, struct intel_region *region)
345 {
346 struct intel_buffer_object *pbo = region->pbo;
347 GLboolean was_locked = intel->locked;
348
349 if (intel == NULL)
350 return;
351
352 intel_region_release_pbo(intel, region);
353
354 assert(region->cpp * region->pitch * region->height == pbo->Base.Size);
355
356 DBG("%s (%d bytes)\n", __FUNCTION__, pbo->Base.Size);
357
358 /* Now blit from the texture buffer to the new buffer:
359 */
360
361 intel_batchbuffer_flush(intel->batch);
362
363 was_locked = intel->locked;
364 if (intel->locked)
365 LOCK_HARDWARE(intel);
366
367 intelEmitCopyBlit(intel,
368 region->cpp,
369 region->pitch, region->buffer, 0, region->tiled,
370 region->pitch, pbo->buffer, 0, region->tiled,
371 0, 0, 0, 0,
372 region->pitch, region->height,
373 GL_COPY);
374
375 intel_batchbuffer_flush(intel->batch);
376
377 if (was_locked)
378 UNLOCK_HARDWARE(intel);
379 }
380
381 dri_bo *
382 intel_region_buffer(struct intel_context *intel,
383 struct intel_region *region, GLuint flag)
384 {
385 if (region->pbo) {
386 if (flag == INTEL_WRITE_PART)
387 intel_region_cow(intel, region);
388 else if (flag == INTEL_WRITE_FULL)
389 intel_region_release_pbo(intel, region);
390 }
391
392 return region->buffer;
393 }
394
395 static struct intel_region *
396 intel_recreate_static(struct intel_context *intel,
397 const char *name,
398 struct intel_region *region,
399 intelRegion *region_desc,
400 GLuint mem_type)
401 {
402 intelScreenPrivate *intelScreen = intel->intelScreen;
403
404 if (region == NULL) {
405 region = calloc(sizeof(*region), 1);
406 region->refcount = 1;
407 }
408
409 region->cpp = intelScreen->cpp;
410 region->pitch = region_desc->pitch / intelScreen->cpp;
411 region->height = intelScreen->height; /* needed? */
412 region->tiled = region_desc->tiled;
413
414 if (intel->ttm) {
415 assert(region_desc->bo_handle != -1);
416 region->buffer = intel_ttm_bo_create_from_handle(intel->bufmgr,
417 name,
418 region_desc->bo_handle);
419 } else {
420 region->buffer = dri_bo_alloc_static(intel->bufmgr,
421 name,
422 region_desc->offset,
423 region_desc->pitch *
424 intelScreen->height,
425 region_desc->map,
426 DRM_BO_FLAG_MEM_TT);
427 }
428
429 assert(region->buffer != NULL);
430
431 return region;
432 }
433
434 /**
435 * Create intel_region structs to describe the static front, back, and depth
436 * buffers created by the xserver.
437 *
438 * Although FBO's mean we now no longer use these as render targets in
439 * all circumstances, they won't go away until the back and depth
440 * buffers become private, and the front buffer will remain even then.
441 *
442 * Note that these don't allocate video memory, just describe
443 * allocations alread made by the X server.
444 */
445 void
446 intel_recreate_static_regions(struct intel_context *intel)
447 {
448 intelScreenPrivate *intelScreen = intel->intelScreen;
449
450 intel->front_region =
451 intel_recreate_static(intel, "front",
452 intel->front_region,
453 &intelScreen->front,
454 DRM_BO_FLAG_MEM_TT);
455
456 intel->back_region =
457 intel_recreate_static(intel, "back",
458 intel->back_region,
459 &intelScreen->back,
460 DRM_BO_FLAG_MEM_TT);
461
462 if (intelScreen->third.handle) {
463 intel->third_region =
464 intel_recreate_static(intel, "third",
465 intel->third_region,
466 &intelScreen->third,
467 DRM_BO_FLAG_MEM_TT);
468 }
469
470 /* Still assumes front.cpp == depth.cpp. We can kill this when we move to
471 * private buffers.
472 */
473 intel->depth_region =
474 intel_recreate_static(intel, "depth",
475 intel->depth_region,
476 &intelScreen->depth,
477 DRM_BO_FLAG_MEM_TT);
478 }