[D3D8][D3D9][DDRAW][WINED3D] Sync with Wine Staging 3.3. CORE-14434
[reactos.git] / dll / directx / wine / wined3d / resource.c
index 0788146..8b7f17b 100644 (file)
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include "config.h"
+#include "wine/port.h"
 #include "wined3d_private.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
 WINE_DECLARE_DEBUG_CHANNEL(d3d_perf);
 
-static DWORD resource_access_from_pool(enum wined3d_pool pool)
-{
-    switch (pool)
-    {
-        case WINED3D_POOL_DEFAULT:
-            return WINED3D_RESOURCE_ACCESS_GPU;
-
-        case WINED3D_POOL_MANAGED:
-            return WINED3D_RESOURCE_ACCESS_GPU | WINED3D_RESOURCE_ACCESS_CPU;
-
-        case WINED3D_POOL_SCRATCH:
-        case WINED3D_POOL_SYSTEM_MEM:
-            return WINED3D_RESOURCE_ACCESS_CPU;
-
-        default:
-            FIXME("Unhandled pool %#x.\n", pool);
-            return 0;
-    }
-}
-
 static void resource_check_usage(DWORD usage)
 {
-    static const DWORD handled = WINED3DUSAGE_RENDERTARGET
+    static DWORD handled = WINED3DUSAGE_RENDERTARGET
             | WINED3DUSAGE_DEPTHSTENCIL
             | WINED3DUSAGE_WRITEONLY
             | WINED3DUSAGE_DYNAMIC
-            | WINED3DUSAGE_AUTOGENMIPMAP
             | WINED3DUSAGE_STATICDECL
             | WINED3DUSAGE_OVERLAY
+            | WINED3DUSAGE_SCRATCH
             | WINED3DUSAGE_PRIVATE
             | WINED3DUSAGE_LEGACY_CUBEMAP
             | WINED3DUSAGE_TEXTURE;
@@ -66,16 +48,19 @@ static void resource_check_usage(DWORD usage)
      * driver. */
 
     if (usage & ~handled)
+    {
         FIXME("Unhandled usage flags %#x.\n", usage & ~handled);
+        handled |= usage;
+    }
     if ((usage & (WINED3DUSAGE_DYNAMIC | WINED3DUSAGE_WRITEONLY)) == WINED3DUSAGE_DYNAMIC)
         WARN_(d3d_perf)("WINED3DUSAGE_DYNAMIC used without WINED3DUSAGE_WRITEONLY.\n");
 }
 
 HRESULT resource_init(struct wined3d_resource *resource, struct wined3d_device *device,
         enum wined3d_resource_type type, const struct wined3d_format *format,
-        enum wined3d_multisample_type multisample_type, UINT multisample_quality,
-        DWORD usage, enum wined3d_pool pool, UINT width, UINT height, UINT depth, UINT size,
-        void *parent, const struct wined3d_parent_ops *parent_ops,
+        enum wined3d_multisample_type multisample_type, unsigned int multisample_quality,
+        unsigned int usage, unsigned int access, unsigned int width, unsigned int height, unsigned int depth,
+        unsigned int size, void *parent, const struct wined3d_parent_ops *parent_ops,
         const struct wined3d_resource_ops *resource_ops)
 {
     enum wined3d_gl_resource_type base_type = WINED3D_GL_RES_TYPE_COUNT;
@@ -93,6 +78,7 @@ HRESULT resource_init(struct wined3d_resource *resource, struct wined3d_device *
     resource_types[] =
     {
         {WINED3D_RTYPE_BUFFER,      0,                              WINED3D_GL_RES_TYPE_BUFFER},
+        {WINED3D_RTYPE_TEXTURE_1D,  0,                              WINED3D_GL_RES_TYPE_TEX_1D},
         {WINED3D_RTYPE_TEXTURE_2D,  0,                              WINED3D_GL_RES_TYPE_TEX_2D},
         {WINED3D_RTYPE_TEXTURE_2D,  0,                              WINED3D_GL_RES_TYPE_TEX_RECT},
         {WINED3D_RTYPE_TEXTURE_2D,  0,                              WINED3D_GL_RES_TYPE_RB},
@@ -102,6 +88,13 @@ HRESULT resource_init(struct wined3d_resource *resource, struct wined3d_device *
 
     resource_check_usage(usage);
 
+    if (usage & WINED3DUSAGE_SCRATCH && access & WINED3D_RESOURCE_ACCESS_GPU)
+    {
+        ERR("Trying to create a scratch resource with access flags %s.\n",
+                wined3d_debug_resource_access(access));
+        return WINED3DERR_INVALIDCALL;
+    }
+
     for (i = 0; i < ARRAY_SIZE(resource_types); ++i)
     {
         if (resource_types[i].type != type
@@ -155,7 +148,7 @@ HRESULT resource_init(struct wined3d_resource *resource, struct wined3d_device *
              * Use 2D textures, the texture code will pad to a power of 2 size. */
             gl_type = WINED3D_GL_RES_TYPE_TEX_2D;
         }
-        else if (pool == WINED3D_POOL_SCRATCH)
+        else if (usage & WINED3DUSAGE_SCRATCH)
         {
             /* Needed for proper format information. */
             gl_type = base_type;
@@ -188,10 +181,7 @@ HRESULT resource_init(struct wined3d_resource *resource, struct wined3d_device *
     resource->multisample_type = multisample_type;
     resource->multisample_quality = multisample_quality;
     resource->usage = usage;
-    resource->pool = pool;
-    resource->access_flags = resource_access_from_pool(pool);
-    if (usage & WINED3DUSAGE_DYNAMIC)
-        resource->access_flags |= WINED3D_RESOURCE_ACCESS_CPU;
+    resource->access = access;
     resource->width = width;
     resource->height = height;
     resource->depth = depth;
@@ -218,7 +208,7 @@ HRESULT resource_init(struct wined3d_resource *resource, struct wined3d_device *
     if (!(usage & WINED3DUSAGE_PRIVATE))
     {
         /* Check that we have enough video ram left */
-        if (pool == WINED3D_POOL_DEFAULT && device->wined3d->flags & WINED3D_VIDMEM_ACCOUNTING)
+        if (!(access & WINED3D_RESOURCE_ACCESS_CPU) && device->wined3d->flags & WINED3D_VIDMEM_ACCOUNTING)
         {
             if (size > wined3d_device_get_available_texture_mem(device))
             {
@@ -252,7 +242,7 @@ void resource_cleanup(struct wined3d_resource *resource)
 
     if (!(resource->usage & WINED3DUSAGE_PRIVATE))
     {
-        if (resource->pool == WINED3D_POOL_DEFAULT && d3d->flags & WINED3D_VIDMEM_ACCOUNTING)
+        if (!(resource->access & WINED3D_RESOURCE_ACCESS_CPU) && d3d->flags & WINED3D_VIDMEM_ACCOUNTING)
         {
             TRACE("Decrementing device memory pool by %u.\n", resource->size);
             adapter_adjust_memory(resource->device->adapter, (INT64)0 - resource->size);
@@ -274,7 +264,7 @@ DWORD CDECL wined3d_resource_set_priority(struct wined3d_resource *resource, DWO
 {
     DWORD prev;
 
-    if (resource->pool != WINED3D_POOL_MANAGED)
+    if (!wined3d_resource_access_is_managed(resource->access))
     {
         WARN("Called on non-managed resource %p, ignoring.\n", resource);
         return 0;
@@ -309,7 +299,7 @@ void CDECL wined3d_resource_get_desc(const struct wined3d_resource *resource, st
     desc->multisample_type = resource->multisample_type;
     desc->multisample_quality = resource->multisample_quality;
     desc->usage = resource->usage;
-    desc->pool = resource->pool;
+    desc->access = resource->access;
     desc->width = resource->width;
     desc->height = resource->height;
     desc->depth = resource->depth;
@@ -320,17 +310,17 @@ static DWORD wined3d_resource_sanitise_map_flags(const struct wined3d_resource *
 {
     /* Not all flags make sense together, but Windows never returns an error.
      * Catch the cases that could cause issues. */
-    if (flags & WINED3D_MAP_READONLY)
+    if (flags & WINED3D_MAP_READ)
     {
         if (flags & WINED3D_MAP_DISCARD)
         {
-            WARN("WINED3D_MAP_READONLY combined with WINED3D_MAP_DISCARD, ignoring flags.\n");
-            return 0;
+            WARN("WINED3D_MAP_READ combined with WINED3D_MAP_DISCARD, ignoring flags.\n");
+            return flags & (WINED3D_MAP_READ | WINED3D_MAP_WRITE);
         }
         if (flags & WINED3D_MAP_NOOVERWRITE)
         {
-            WARN("WINED3D_MAP_READONLY combined with WINED3D_MAP_NOOVERWRITE, ignoring flags.\n");
-            return 0;
+            WARN("WINED3D_MAP_READ combined with WINED3D_MAP_NOOVERWRITE, ignoring flags.\n");
+            return flags & (WINED3D_MAP_READ | WINED3D_MAP_WRITE);
         }
     }
     else if (flags & (WINED3D_MAP_DISCARD | WINED3D_MAP_NOOVERWRITE))
@@ -338,7 +328,7 @@ static DWORD wined3d_resource_sanitise_map_flags(const struct wined3d_resource *
         if (!(resource->usage & WINED3DUSAGE_DYNAMIC))
         {
             WARN("DISCARD or NOOVERWRITE map on non-dynamic buffer, ignoring.\n");
-            return 0;
+            return flags & (WINED3D_MAP_READ | WINED3D_MAP_WRITE);
         }
         if ((flags & (WINED3D_MAP_DISCARD | WINED3D_MAP_NOOVERWRITE))
                 == (WINED3D_MAP_DISCARD | WINED3D_MAP_NOOVERWRITE))
@@ -357,12 +347,38 @@ HRESULT CDECL wined3d_resource_map(struct wined3d_resource *resource, unsigned i
     TRACE("resource %p, sub_resource_idx %u, map_desc %p, box %s, flags %#x.\n",
             resource, sub_resource_idx, map_desc, debug_box(box), flags);
 
+    if (!(flags & (WINED3D_MAP_READ | WINED3D_MAP_WRITE)))
+    {
+        WARN("No read/write flags specified.\n");
+        return E_INVALIDARG;
+    }
+
+    if ((flags & WINED3D_MAP_READ) && !(resource->access & WINED3D_RESOURCE_ACCESS_MAP_R))
+    {
+        WARN("Resource does not have MAP_R access.\n");
+        return E_INVALIDARG;
+    }
+
+    if ((flags & WINED3D_MAP_WRITE) && !(resource->access & WINED3D_RESOURCE_ACCESS_MAP_W))
+    {
+        WARN("Resource does not have MAP_W access.\n");
+        return E_INVALIDARG;
+    }
+
     flags = wined3d_resource_sanitise_map_flags(resource, flags);
     wined3d_resource_wait_idle(resource);
 
     return wined3d_cs_map(resource->device->cs, resource, sub_resource_idx, map_desc, box, flags);
 }
 
+HRESULT CDECL wined3d_resource_map_info(struct wined3d_resource *resource, unsigned int sub_resource_idx,
+        struct wined3d_map_info *info, DWORD flags)
+{
+    TRACE("resource %p, sub_resource_idx %u.\n", resource, sub_resource_idx);
+
+    return resource->resource_ops->resource_map_info(resource, sub_resource_idx, info, flags);
+}
+
 HRESULT CDECL wined3d_resource_unmap(struct wined3d_resource *resource, unsigned int sub_resource_idx)
 {
     TRACE("resource %p, sub_resource_idx %u.\n", resource, sub_resource_idx);
@@ -370,6 +386,99 @@ HRESULT CDECL wined3d_resource_unmap(struct wined3d_resource *resource, unsigned
     return wined3d_cs_unmap(resource->device->cs, resource, sub_resource_idx);
 }
 
+UINT CDECL wined3d_resource_update_info(struct wined3d_resource *resource, unsigned int sub_resource_idx,
+        const struct wined3d_box *box, unsigned int row_pitch, unsigned int depth_pitch)
+{
+    unsigned int width, height, depth;
+    struct wined3d_box b;
+    UINT data_size;
+
+    TRACE("resource %p, sub_resource_idx %u, box %s, row_pitch %u, depth_pitch %u.\n",
+            resource, sub_resource_idx, debug_box(box), row_pitch, depth_pitch);
+
+    if (resource->type == WINED3D_RTYPE_BUFFER)
+    {
+        if (sub_resource_idx > 0)
+        {
+            WARN("Invalid sub_resource_idx %u.\n", sub_resource_idx);
+            return 0;
+        }
+
+        width = resource->size;
+        height = 1;
+        depth = 1;
+    }
+    else if (resource->type == WINED3D_RTYPE_TEXTURE_1D ||
+            resource->type == WINED3D_RTYPE_TEXTURE_2D || resource->type == WINED3D_RTYPE_TEXTURE_3D)
+    {
+        struct wined3d_texture *texture = texture_from_resource(resource);
+        unsigned int level;
+
+        if (sub_resource_idx >= texture->level_count * texture->layer_count)
+        {
+            WARN("Invalid sub_resource_idx %u.\n", sub_resource_idx);
+            return 0;
+        }
+
+        level = sub_resource_idx % texture->level_count;
+        width = wined3d_texture_get_level_width(texture, level);
+        height = wined3d_texture_get_level_height(texture, level);
+        depth = wined3d_texture_get_level_depth(texture, level);
+    }
+    else
+    {
+        FIXME("Not implemented for %s resources.\n", debug_d3dresourcetype(resource->type));
+        return 0;
+    }
+
+    if (!box)
+    {
+        wined3d_box_set(&b, 0, 0, width, height, 0, depth);
+        box = &b;
+    }
+    else if (box->left >= box->right || box->right > width
+            || box->top >= box->bottom || box->bottom > height
+            || box->front >= box->back || box->back > depth)
+    {
+        WARN("Invalid box %s specified.\n", debug_box(box));
+        return 0;
+    }
+
+    if (resource->format_flags & WINED3DFMT_FLAG_BLOCKS)
+    {
+        if (resource->type != WINED3D_RTYPE_TEXTURE_2D)
+        {
+            FIXME("Calculation of block formats not implemented for %s resources.\n", debug_d3dresourcetype(resource->type));
+            return 0;
+        }
+
+        height  = (box->bottom - box->top  + resource->format->block_height - 1) / resource->format->block_height;
+        width   = (box->right  - box->left + resource->format->block_width  - 1) / resource->format->block_width;
+        return (height - 1) * row_pitch + width * resource->format->block_byte_count;
+    }
+
+    data_size = 0;
+    switch (resource->type)
+    {
+        case WINED3D_RTYPE_TEXTURE_3D:
+            data_size += (box->back - box->front - 1) * depth_pitch;
+            /* fall-through */
+        case WINED3D_RTYPE_TEXTURE_2D:
+            data_size += (box->bottom - box->top - 1) * row_pitch;
+            /* fall-through */
+        case WINED3D_RTYPE_TEXTURE_1D:
+            data_size += (box->right - box->left) * resource->format->byte_count;
+            break;
+        case WINED3D_RTYPE_BUFFER:
+            data_size = box->right - box->left;
+            break;
+        case WINED3D_RTYPE_NONE:
+            break;
+    }
+
+    return data_size;
+}
+
 void CDECL wined3d_resource_preload(struct wined3d_resource *resource)
 {
     wined3d_cs_emit_preload_resource(resource->device->cs, resource);
@@ -381,7 +490,7 @@ BOOL wined3d_resource_allocate_sysmem(struct wined3d_resource *resource)
     SIZE_T align = RESOURCE_ALIGNMENT - 1 + sizeof(*p);
     void *mem;
 
-    if (!(mem = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, resource->size + align)))
+    if (!(mem = heap_alloc_zero(resource->size + align)))
         return FALSE;
 
     p = (void **)(((ULONG_PTR)mem + align) & ~(RESOURCE_ALIGNMENT - 1)) - 1;
@@ -399,7 +508,7 @@ void wined3d_resource_free_sysmem(struct wined3d_resource *resource)
     if (!p)
         return;
 
-    HeapFree(GetProcessHeap(), 0, *(--p));
+    heap_free(*(--p));
     resource->heap_memory = NULL;
 }
 
@@ -407,9 +516,9 @@ GLbitfield wined3d_resource_gl_map_flags(DWORD d3d_flags)
 {
     GLbitfield ret = 0;
 
-    if (!(d3d_flags & WINED3D_MAP_READONLY))
+    if (d3d_flags & WINED3D_MAP_WRITE)
         ret |= GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT;
-    if (!(d3d_flags & (WINED3D_MAP_DISCARD | WINED3D_MAP_NOOVERWRITE)))
+    if (d3d_flags & WINED3D_MAP_READ)
         ret |= GL_MAP_READ_BIT;
 
     if (d3d_flags & WINED3D_MAP_DISCARD)
@@ -422,11 +531,17 @@ GLbitfield wined3d_resource_gl_map_flags(DWORD d3d_flags)
 
 GLenum wined3d_resource_gl_legacy_map_flags(DWORD d3d_flags)
 {
-    if (d3d_flags & WINED3D_MAP_READONLY)
-        return GL_READ_ONLY_ARB;
-    if (d3d_flags & (WINED3D_MAP_DISCARD | WINED3D_MAP_NOOVERWRITE))
-        return GL_WRITE_ONLY_ARB;
-    return GL_READ_WRITE_ARB;
+    switch (d3d_flags & (WINED3D_MAP_READ | WINED3D_MAP_WRITE))
+    {
+        case WINED3D_MAP_READ:
+            return GL_READ_ONLY_ARB;
+
+        case WINED3D_MAP_WRITE:
+            return GL_WRITE_ONLY_ARB;
+
+        default:
+            return GL_READ_WRITE_ARB;
+    }
 }
 
 BOOL wined3d_resource_is_offscreen(struct wined3d_resource *resource)
@@ -453,11 +568,23 @@ BOOL wined3d_resource_is_offscreen(struct wined3d_resource *resource)
 void wined3d_resource_update_draw_binding(struct wined3d_resource *resource)
 {
     if (!wined3d_resource_is_offscreen(resource) || wined3d_settings.offscreen_rendering_mode != ORM_FBO)
+    {
         resource->draw_binding = WINED3D_LOCATION_DRAWABLE;
+    }
     else if (resource->multisample_type)
-        resource->draw_binding = WINED3D_LOCATION_RB_MULTISAMPLE;
+    {
+        const struct wined3d_gl_info *gl_info = &resource->device->adapter->gl_info;
+        if (gl_info->supported[ARB_TEXTURE_MULTISAMPLE])
+            resource->draw_binding = WINED3D_LOCATION_TEXTURE_RGB;
+        else
+            resource->draw_binding = WINED3D_LOCATION_RB_MULTISAMPLE;
+    }
     else if (resource->gl_type == WINED3D_GL_RES_TYPE_RB)
+    {
         resource->draw_binding = WINED3D_LOCATION_RB_RESOLVED;
+    }
     else
+    {
         resource->draw_binding = WINED3D_LOCATION_TEXTURE_RGB;
+    }
 }