Merge commit 'origin/gallium-0.1' into gallium-0.2
[mesa.git] / src / gallium / auxiliary / pipebuffer / pb_bufmgr_debug.c
index affa6aa85c42bbe6fe83d8bf6a645c955d10317a..62639fe1c876fa95dea31de32a361bda06c5fc0e 100644 (file)
@@ -29,7 +29,7 @@
  * \file
  * Debug buffer manager to detect buffer under- and overflows.
  * 
- * \author José Fonseca <jrfonseca@tungstengraphics.com>
+ * \author Jose Fonseca <jrfonseca@tungstengraphics.com>
  */
 
 
@@ -37,7 +37,8 @@
 #include "pipe/p_debug.h"
 #include "pipe/p_winsys.h"
 #include "pipe/p_thread.h"
-#include "pipe/p_util.h"
+#include "util/u_math.h"
+#include "util/u_memory.h"
 #include "util/u_double_list.h"
 #include "util/u_time.h"
 
@@ -109,7 +110,7 @@ static const uint8_t random_pattern[32] = {
 static INLINE void 
 fill_random_pattern(uint8_t *dst, size_t size)
 {
-   unsigned i = 0;
+   size_t i = 0;
    while(size--) {
       *dst++ = random_pattern[i++];
       i &= sizeof(random_pattern) - 1;
@@ -118,40 +119,98 @@ fill_random_pattern(uint8_t *dst, size_t size)
 
 
 static INLINE boolean 
-check_random_pattern(const uint8_t *dst, size_t size) 
+check_random_pattern(const uint8_t *dst, size_t size, 
+                     size_t *min_ofs, size_t *max_ofs) 
 {
-   unsigned i = 0;
-   while(size--) {
-      if(*dst++ != random_pattern[i++])
-        return FALSE;
-      i &= sizeof(random_pattern) - 1;
+   boolean result = TRUE;
+   size_t i;
+   *min_ofs = size;
+   *max_ofs = 0;
+   for(i = 0; i < size; ++i) {
+      if(*dst++ != random_pattern[i % sizeof(random_pattern)]) {
+         *min_ofs = MIN2(*min_ofs, i);
+         *max_ofs = MAX2(*max_ofs, i);
+        result = FALSE;
+      }
    }
-   return TRUE;
+   return result;
 }
 
 
 static void
-pb_debug_buffer_destroy(struct pb_buffer *_buf)
+pb_debug_buffer_fill(struct pb_debug_buffer *buf)
 {
-   struct pb_debug_buffer *buf = pb_debug_buffer(_buf);  
    uint8_t *map;
    
-   assert(!buf->base.base.refcount);
+   map = pb_map(buf->buffer, PIPE_BUFFER_USAGE_CPU_WRITE);
+   assert(map);
+   if(map) {
+      fill_random_pattern(map, buf->underflow_size);
+      fill_random_pattern(map + buf->underflow_size + buf->base.base.size, 
+                          buf->overflow_size);
+      pb_unmap(buf->buffer);
+   }
+}
+
+
+/**
+ * Check for under/over flows.
+ * 
+ * Should be called with the buffer unmaped.
+ */
+static void
+pb_debug_buffer_check(struct pb_debug_buffer *buf)
+{
+   uint8_t *map;
    
    map = pb_map(buf->buffer, PIPE_BUFFER_USAGE_CPU_READ);
    assert(map);
    if(map) {
-      if(!check_random_pattern(map, buf->underflow_size)) {
-        debug_error("buffer underflow detected\n");
-        debug_assert(0);
+      boolean underflow, overflow;
+      size_t min_ofs, max_ofs;
+      
+      underflow = !check_random_pattern(map, buf->underflow_size, 
+                                        &min_ofs, &max_ofs);
+      if(underflow) {
+         debug_printf("buffer underflow (offset -%u%s to -%u bytes) detected\n",
+                      buf->underflow_size - min_ofs,
+                      min_ofs == 0 ? "+" : "",
+                      buf->underflow_size - max_ofs);
       }
-      if(!check_random_pattern(map + buf->underflow_size + buf->base.base.size, 
-                               buf->overflow_size)) {
-        debug_error("buffer overflow detected\n");
-        debug_assert(0);
+      
+      overflow = !check_random_pattern(map + buf->underflow_size + buf->base.base.size, 
+                                       buf->overflow_size, 
+                                       &min_ofs, &max_ofs);
+      if(overflow) {
+         debug_printf("buffer overflow (size %u plus offset %u to %u%s bytes) detected\n",
+                      buf->base.base.size,
+                      min_ofs,
+                      max_ofs,
+                      max_ofs == buf->overflow_size - 1 ? "+" : "");
       }
+      
+      debug_assert(!underflow && !overflow);
+
+      /* re-fill if not aborted */
+      if(underflow)
+         fill_random_pattern(map, buf->underflow_size);
+      if(overflow)
+         fill_random_pattern(map + buf->underflow_size + buf->base.base.size, 
+                             buf->overflow_size);
+
       pb_unmap(buf->buffer);
    }
+}
+
+
+static void
+pb_debug_buffer_destroy(struct pb_buffer *_buf)
+{
+   struct pb_debug_buffer *buf = pb_debug_buffer(_buf);  
+   
+   assert(!buf->base.base.refcount);
+   
+   pb_debug_buffer_check(buf);
 
    pb_reference(&buf->buffer, NULL);
    FREE(buf);
@@ -163,9 +222,14 @@ pb_debug_buffer_map(struct pb_buffer *_buf,
                     unsigned flags)
 {
    struct pb_debug_buffer *buf = pb_debug_buffer(_buf);
-   void *map = pb_map(buf->buffer, flags);
+   void *map;
+   
+   pb_debug_buffer_check(buf);
+
+   map = pb_map(buf->buffer, flags);
    if(!map)
       return NULL;
+   
    return (uint8_t *)map + buf->underflow_size;
 }
 
@@ -175,6 +239,8 @@ pb_debug_buffer_unmap(struct pb_buffer *_buf)
 {
    struct pb_debug_buffer *buf = pb_debug_buffer(_buf);   
    pb_unmap(buf->buffer);
+   
+   pb_debug_buffer_check(buf);
 }
 
 
@@ -189,11 +255,35 @@ pb_debug_buffer_get_base_buffer(struct pb_buffer *_buf,
 }
 
 
+static enum pipe_error 
+pb_debug_buffer_validate(struct pb_buffer *_buf, 
+                         struct pb_validate *vl,
+                         unsigned flags)
+{
+   struct pb_debug_buffer *buf = pb_debug_buffer(_buf);
+   
+   pb_debug_buffer_check(buf);
+
+   return pb_validate(buf->buffer, vl, flags);
+}
+
+
+static void
+pb_debug_buffer_fence(struct pb_buffer *_buf, 
+                      struct pipe_fence_handle *fence)
+{
+   struct pb_debug_buffer *buf = pb_debug_buffer(_buf);
+   pb_fence(buf->buffer, fence);
+}
+
+
 const struct pb_vtbl 
 pb_debug_buffer_vtbl = {
       pb_debug_buffer_destroy,
       pb_debug_buffer_map,
       pb_debug_buffer_unmap,
+      pb_debug_buffer_validate,
+      pb_debug_buffer_fence,
       pb_debug_buffer_get_base_buffer
 };
 
@@ -207,7 +297,6 @@ pb_debug_manager_create_buffer(struct pb_manager *_mgr,
    struct pb_debug_buffer *buf;
    struct pb_desc real_desc;
    size_t real_size;
-   uint8_t *map;
    
    buf = CALLOC_STRUCT(pb_debug_buffer);
    if(!buf)
@@ -242,18 +331,22 @@ pb_debug_manager_create_buffer(struct pb_manager *_mgr,
    buf->underflow_size = mgr->band_size;
    buf->overflow_size = buf->buffer->base.size - buf->underflow_size - size;
    
-   map = pb_map(buf->buffer, PIPE_BUFFER_USAGE_CPU_WRITE);
-   assert(map);
-   if(map) {
-      fill_random_pattern(map, buf->underflow_size);
-      fill_random_pattern(map + buf->underflow_size + size, buf->overflow_size);
-      pb_unmap(buf->buffer);
-   }
+   pb_debug_buffer_fill(buf);
    
    return &buf->base;
 }
 
 
+static void
+pb_debug_manager_flush(struct pb_manager *_mgr)
+{
+   struct pb_debug_manager *mgr = pb_debug_manager(_mgr);
+   assert(mgr->provider->flush);
+   if(mgr->provider->flush)
+      mgr->provider->flush(mgr->provider);
+}
+
+
 static void
 pb_debug_manager_destroy(struct pb_manager *_mgr)
 {
@@ -277,6 +370,7 @@ pb_debug_manager_create(struct pb_manager *provider, size_t band_size)
 
    mgr->base.destroy = pb_debug_manager_destroy;
    mgr->base.create_buffer = pb_debug_manager_create_buffer;
+   mgr->base.flush = pb_debug_manager_flush;
    mgr->provider = provider;
    mgr->band_size = band_size;