intel_regions.c revision e1e48ea15c1fe448f0b69e086b66c1123dc98bb7
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 "main/hash.h"
46#include "intel_context.h"
47#include "intel_regions.h"
48#include "intel_blit.h"
49#include "intel_buffer_objects.h"
50#include "intel_bufmgr.h"
51#include "intel_batchbuffer.h"
52
53#define FILE_DEBUG_FLAG DEBUG_REGION
54
55/* This should be set to the maximum backtrace size desired.
56 * Set it to 0 to disable backtrace debugging.
57 */
58#define DEBUG_BACKTRACE_SIZE 0
59
60#if DEBUG_BACKTRACE_SIZE == 0
61/* Use the standard debug output */
62#define _DBG(...) DBG(__VA_ARGS__)
63#else
64/* Use backtracing debug output */
65#define _DBG(...) {debug_backtrace(); DBG(__VA_ARGS__);}
66
67/* Backtracing debug support */
68#include <execinfo.h>
69
70static void
71debug_backtrace(void)
72{
73   void *trace[DEBUG_BACKTRACE_SIZE];
74   char **strings = NULL;
75   int traceSize;
76   register int i;
77
78   traceSize = backtrace(trace, DEBUG_BACKTRACE_SIZE);
79   strings = backtrace_symbols(trace, traceSize);
80   if (strings == NULL) {
81      DBG("no backtrace:");
82      return;
83   }
84
85   /* Spit out all the strings with a colon separator.  Ignore
86    * the first, since we don't really care about the call
87    * to debug_backtrace() itself.  Skip until the final "/" in
88    * the trace to avoid really long lines.
89    */
90   for (i = 1; i < traceSize; i++) {
91      char *p = strings[i], *slash = strings[i];
92      while (*p) {
93         if (*p++ == '/') {
94            slash = p;
95         }
96      }
97
98      DBG("%s:", slash);
99   }
100
101   /* Free up the memory, and we're done */
102   free(strings);
103}
104
105#endif
106
107
108
109/* XXX: Thread safety?
110 */
111GLubyte *
112intel_region_map(struct intel_context *intel, struct intel_region *region)
113{
114   intelFlush(&intel->ctx);
115
116   _DBG("%s %p\n", __FUNCTION__, region);
117   if (!region->map_refcount++) {
118      if (region->pbo)
119         intel_region_cow(intel, region);
120
121      if (region->tiling != I915_TILING_NONE)
122	 drm_intel_gem_bo_map_gtt(region->buffer);
123      else
124	 dri_bo_map(region->buffer, GL_TRUE);
125      region->map = region->buffer->virtual;
126   }
127
128   return region->map;
129}
130
131void
132intel_region_unmap(struct intel_context *intel, struct intel_region *region)
133{
134   _DBG("%s %p\n", __FUNCTION__, region);
135   if (!--region->map_refcount) {
136      if (region->tiling != I915_TILING_NONE)
137	 drm_intel_gem_bo_unmap_gtt(region->buffer);
138      else
139	 dri_bo_unmap(region->buffer);
140      region->map = NULL;
141   }
142}
143
144static struct intel_region *
145intel_region_alloc_internal(struct intel_context *intel,
146			    GLuint cpp,
147			    GLuint width, GLuint height, GLuint pitch,
148			    dri_bo *buffer)
149{
150   struct intel_region *region;
151
152   if (buffer == NULL) {
153      _DBG("%s <-- NULL\n", __FUNCTION__);
154      return NULL;
155   }
156
157   region = calloc(sizeof(*region), 1);
158   region->cpp = cpp;
159   region->width = width;
160   region->height = height;
161   region->pitch = pitch;
162   region->refcount = 1;
163   region->buffer = buffer;
164
165   /* Default to no tiling */
166   region->tiling = I915_TILING_NONE;
167
168   _DBG("%s <-- %p\n", __FUNCTION__, region);
169   return region;
170}
171
172struct intel_region *
173intel_region_alloc(struct intel_context *intel,
174		   uint32_t tiling,
175                   GLuint cpp, GLuint width, GLuint height,
176		   GLboolean expect_accelerated_upload)
177{
178   dri_bo *buffer;
179   struct intel_region *region;
180   unsigned long flags = 0;
181   unsigned long aligned_pitch;
182
183   if (expect_accelerated_upload)
184      flags |= BO_ALLOC_FOR_RENDER;
185
186   buffer = drm_intel_bo_alloc_tiled(intel->bufmgr, "region",
187				     width, height, cpp,
188				     &tiling, &aligned_pitch, flags);
189
190   region = intel_region_alloc_internal(intel, cpp, width, height,
191					aligned_pitch / cpp, buffer);
192   region->tiling = tiling;
193
194   return region;
195}
196
197struct intel_region *
198intel_region_alloc_for_handle(struct intel_context *intel,
199			      GLuint cpp,
200			      GLuint width, GLuint height, GLuint pitch,
201			      GLuint handle, const char *name)
202{
203   struct intel_region *region, *dummy;
204   dri_bo *buffer;
205   int ret;
206   uint32_t bit_6_swizzle;
207
208   region = _mesa_HashLookup(intel->intelScreen->named_regions, handle);
209   if (region != NULL) {
210      dummy = NULL;
211      if (region->width != width || region->height != height ||
212	  region->cpp != cpp || region->pitch != pitch) {
213	 fprintf(stderr,
214		 "Region for name %d already exists but is not compatible\n",
215		 handle);
216	 return NULL;
217      }
218      intel_region_reference(&dummy, region);
219      return dummy;
220   }
221
222   buffer = intel_bo_gem_create_from_name(intel->bufmgr, name, handle);
223
224   region = intel_region_alloc_internal(intel, cpp,
225					width, height, pitch, buffer);
226   if (region == NULL)
227      return region;
228
229   ret = dri_bo_get_tiling(region->buffer, &region->tiling,
230			   &bit_6_swizzle);
231   if (ret != 0) {
232      fprintf(stderr, "Couldn't get tiling of buffer %d (%s): %s\n",
233	      handle, name, strerror(-ret));
234      intel_region_release(&region);
235      return NULL;
236   }
237
238   region->name = handle;
239   region->screen = intel->intelScreen;
240   _mesa_HashInsert(intel->intelScreen->named_regions, handle, region);
241
242   return region;
243}
244
245void
246intel_region_reference(struct intel_region **dst, struct intel_region *src)
247{
248   if (src)
249      _DBG("%s %p %d\n", __FUNCTION__, src, src->refcount);
250
251   assert(*dst == NULL);
252   if (src) {
253      src->refcount++;
254      *dst = src;
255   }
256}
257
258void
259intel_region_release(struct intel_region **region_handle)
260{
261   struct intel_region *region = *region_handle;
262
263   if (region == NULL) {
264      _DBG("%s NULL\n", __FUNCTION__);
265      return;
266   }
267
268   _DBG("%s %p %d\n", __FUNCTION__, region, region->refcount - 1);
269
270   ASSERT(region->refcount > 0);
271   region->refcount--;
272
273   if (region->refcount == 0) {
274      assert(region->map_refcount == 0);
275
276      if (region->pbo)
277	 region->pbo->region = NULL;
278      region->pbo = NULL;
279      dri_bo_unreference(region->buffer);
280
281      if (region->name > 0)
282	 _mesa_HashRemove(region->screen->named_regions, region->name);
283
284      free(region);
285   }
286   *region_handle = NULL;
287}
288
289/*
290 * XXX Move this into core Mesa?
291 */
292void
293_mesa_copy_rect(GLubyte * dst,
294                GLuint cpp,
295                GLuint dst_pitch,
296                GLuint dst_x,
297                GLuint dst_y,
298                GLuint width,
299                GLuint height,
300                const GLubyte * src,
301                GLuint src_pitch, GLuint src_x, GLuint src_y)
302{
303   GLuint i;
304
305   dst_pitch *= cpp;
306   src_pitch *= cpp;
307   dst += dst_x * cpp;
308   src += src_x * cpp;
309   dst += dst_y * dst_pitch;
310   src += src_y * src_pitch;
311   width *= cpp;
312
313   if (width == dst_pitch && width == src_pitch)
314      memcpy(dst, src, height * width);
315   else {
316      for (i = 0; i < height; i++) {
317         memcpy(dst, src, width);
318         dst += dst_pitch;
319         src += src_pitch;
320      }
321   }
322}
323
324
325/* Upload data to a rectangular sub-region.  Lots of choices how to do this:
326 *
327 * - memcpy by span to current destination
328 * - upload data as new buffer and blit
329 *
330 * Currently always memcpy.
331 */
332void
333intel_region_data(struct intel_context *intel,
334                  struct intel_region *dst,
335                  GLuint dst_offset,
336                  GLuint dstx, GLuint dsty,
337                  const void *src, GLuint src_pitch,
338                  GLuint srcx, GLuint srcy, GLuint width, GLuint height)
339{
340   _DBG("%s\n", __FUNCTION__);
341
342   if (intel == NULL)
343      return;
344
345   if (dst->pbo) {
346      if (dstx == 0 &&
347          dsty == 0 && width == dst->pitch && height == dst->height)
348         intel_region_release_pbo(intel, dst);
349      else
350         intel_region_cow(intel, dst);
351   }
352
353   intel_prepare_render(intel);
354
355   _mesa_copy_rect(intel_region_map(intel, dst) + dst_offset,
356                   dst->cpp,
357                   dst->pitch,
358                   dstx, dsty, width, height, src, src_pitch, srcx, srcy);
359
360   intel_region_unmap(intel, dst);
361}
362
363/* Copy rectangular sub-regions. Need better logic about when to
364 * push buffers into AGP - will currently do so whenever possible.
365 */
366GLboolean
367intel_region_copy(struct intel_context *intel,
368                  struct intel_region *dst,
369                  GLuint dst_offset,
370                  GLuint dstx, GLuint dsty,
371                  struct intel_region *src,
372                  GLuint src_offset,
373                  GLuint srcx, GLuint srcy, GLuint width, GLuint height,
374		  GLboolean flip,
375		  GLenum logicop)
376{
377   uint32_t src_pitch = src->pitch;
378
379   _DBG("%s\n", __FUNCTION__);
380
381   if (intel == NULL)
382      return GL_FALSE;
383
384   if (dst->pbo) {
385      if (dstx == 0 &&
386          dsty == 0 && width == dst->pitch && height == dst->height)
387         intel_region_release_pbo(intel, dst);
388      else
389         intel_region_cow(intel, dst);
390   }
391
392   assert(src->cpp == dst->cpp);
393
394   if (flip)
395      src_pitch = -src_pitch;
396
397   return intelEmitCopyBlit(intel,
398			    dst->cpp,
399			    src_pitch, src->buffer, src_offset, src->tiling,
400			    dst->pitch, dst->buffer, dst_offset, dst->tiling,
401			    srcx, srcy, dstx, dsty, width, height,
402			    logicop);
403}
404
405/* Attach to a pbo, discarding our data.  Effectively zero-copy upload
406 * the pbo's data.
407 */
408void
409intel_region_attach_pbo(struct intel_context *intel,
410                        struct intel_region *region,
411                        struct intel_buffer_object *pbo)
412{
413   dri_bo *buffer;
414
415   if (region->pbo == pbo)
416      return;
417
418   _DBG("%s %p %p\n", __FUNCTION__, region, pbo);
419
420   /* If there is already a pbo attached, break the cow tie now.
421    * Don't call intel_region_release_pbo() as that would
422    * unnecessarily allocate a new buffer we would have to immediately
423    * discard.
424    */
425   if (region->pbo) {
426      region->pbo->region = NULL;
427      region->pbo = NULL;
428   }
429
430   if (region->buffer) {
431      dri_bo_unreference(region->buffer);
432      region->buffer = NULL;
433   }
434
435   /* make sure pbo has a buffer of its own */
436   buffer = intel_bufferobj_buffer(intel, pbo, INTEL_WRITE_FULL);
437
438   region->pbo = pbo;
439   region->pbo->region = region;
440   dri_bo_reference(buffer);
441   region->buffer = buffer;
442   region->tiling = I915_TILING_NONE;
443}
444
445
446/* Break the COW tie to the pbo and allocate a new buffer.
447 * The pbo gets to keep the data.
448 */
449void
450intel_region_release_pbo(struct intel_context *intel,
451                         struct intel_region *region)
452{
453   _DBG("%s %p\n", __FUNCTION__, region);
454   assert(region->buffer == region->pbo->buffer);
455   region->pbo->region = NULL;
456   region->pbo = NULL;
457   dri_bo_unreference(region->buffer);
458   region->buffer = NULL;
459
460   region->buffer = dri_bo_alloc(intel->bufmgr, "region",
461				 region->pitch * region->cpp * region->height,
462				 64);
463}
464
465/* Break the COW tie to the pbo.  Both the pbo and the region end up
466 * with a copy of the data.
467 */
468void
469intel_region_cow(struct intel_context *intel, struct intel_region *region)
470{
471   struct intel_buffer_object *pbo = region->pbo;
472   GLboolean ok;
473
474   intel_region_release_pbo(intel, region);
475
476   assert(region->cpp * region->pitch * region->height == pbo->Base.Size);
477
478   _DBG("%s %p (%d bytes)\n", __FUNCTION__, region, pbo->Base.Size);
479
480   /* Now blit from the texture buffer to the new buffer:
481    */
482
483   intel_prepare_render(intel);
484   ok = intelEmitCopyBlit(intel,
485                          region->cpp,
486                          region->pitch, pbo->buffer, 0, region->tiling,
487                          region->pitch, region->buffer, 0, region->tiling,
488                          0, 0, 0, 0,
489                          region->pitch, region->height,
490                          GL_COPY);
491   assert(ok);
492}
493
494dri_bo *
495intel_region_buffer(struct intel_context *intel,
496                    struct intel_region *region, GLuint flag)
497{
498   if (region->pbo) {
499      if (flag == INTEL_WRITE_PART)
500         intel_region_cow(intel, region);
501      else if (flag == INTEL_WRITE_FULL)
502         intel_region_release_pbo(intel, region);
503   }
504
505   return region->buffer;
506}
507