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