volume.c 11.5 KB
Newer Older
1 2
/*
 * Copyright 2002-2005 Jason Edmeades
3
 * Copyright 2002-2005 Raphael Junqueira
4
 * Copyright 2005 Oliver Stieber
5
 * Copyright 2009-2011 Henri Verbeet for CodeWeavers
6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 21 22
 */

#include "config.h"
23
#include "wine/port.h"
24 25
#include "wined3d_private.h"

26
WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
27

28
/* Context activation is done by the caller. */
29
static void volume_bind_and_dirtify(const struct wined3d_volume *volume, struct wined3d_context *context)
30
{
31
    struct wined3d_texture *container = volume->container;
32
    DWORD active_sampler;
33 34 35 36 37 38 39 40

    /* We don't need a specific texture unit, but after binding the texture the current unit is dirty.
     * Read the unit back instead of switching to 0, this avoids messing around with the state manager's
     * gl states. The current texture unit should always be a valid one.
     *
     * To be more specific, this is tricky because we can implicitly be called
     * from sampler() in state.c. This means we can't touch anything other than
     * whatever happens to be the currently active texture, or we would risk
41 42
     * marking already applied sampler states dirty again. */
    active_sampler = volume->resource.device->rev_tex_unit_map[context->active_texture];
43

44
    if (active_sampler != WINED3D_UNMAPPED_STAGE)
45
        device_invalidate_state(volume->resource.device, STATE_SAMPLER(active_sampler));
46

47
    container->texture_ops->texture_bind(container, context, FALSE);
48 49
}

50
void volume_add_dirty_box(struct wined3d_volume *volume, const struct wined3d_box *dirty_box)
51
{
52
    volume->dirty = TRUE;
53 54
    if (dirty_box)
    {
55 56 57 58 59 60
        volume->lockedBox.left = min(volume->lockedBox.left, dirty_box->left);
        volume->lockedBox.top = min(volume->lockedBox.top, dirty_box->top);
        volume->lockedBox.front = min(volume->lockedBox.front, dirty_box->front);
        volume->lockedBox.right = max(volume->lockedBox.right, dirty_box->right);
        volume->lockedBox.bottom = max(volume->lockedBox.bottom, dirty_box->bottom);
        volume->lockedBox.back = max(volume->lockedBox.back, dirty_box->back);
61 62 63
    }
    else
    {
64 65 66 67 68 69
        volume->lockedBox.left = 0;
        volume->lockedBox.top = 0;
        volume->lockedBox.front = 0;
        volume->lockedBox.right = volume->resource.width;
        volume->lockedBox.bottom = volume->resource.height;
        volume->lockedBox.back = volume->resource.depth;
70 71 72
    }
}

73
void volume_set_container(struct wined3d_volume *volume, struct wined3d_texture *container)
74 75 76 77 78 79
{
    TRACE("volume %p, container %p.\n", volume, container);

    volume->container = container;
}

80
/* Context activation is done by the caller. */
81
void volume_load(const struct wined3d_volume *volume, struct wined3d_context *context, UINT level, BOOL srgb_mode)
82
{
83
    const struct wined3d_gl_info *gl_info = context->gl_info;
84 85
    const struct wined3d_format *format = volume->resource.format;

86 87
    TRACE("volume %p, context %p, level %u, srgb %#x, format %s (%#x).\n",
            volume, context, level, srgb_mode, debug_d3dformat(format->id), format->id);
88

89
    volume_bind_and_dirtify(volume, context);
90 91

    GL_EXTCALL(glTexImage3DEXT(GL_TEXTURE_3D, level, format->glInternal,
92
            volume->resource.width, volume->resource.height, volume->resource.depth,
93 94 95 96 97 98 99 100 101 102
            0, format->glFormat, format->glType, volume->resource.allocatedMemory));
    checkGLcall("glTexImage3D");

    /* When adding code releasing volume->resource.allocatedMemory to save
     * data keep in mind that GL_UNPACK_CLIENT_STORAGE_APPLE is enabled by
     * default if supported(GL_APPLE_client_storage). Thus do not release
     * volume->resource.allocatedMemory if GL_APPLE_client_storage is
     * supported. */
}

103
/* Do not call while under the GL lock. */
104
static void volume_unload(struct wined3d_resource *resource)
105 106 107 108 109 110 111 112 113
{
    TRACE("texture %p.\n", resource);

    /* The whole content is shadowed on This->resource.allocatedMemory, and
     * the texture name is managed by the VolumeTexture container. */

    resource_unload(resource);
}

114
ULONG CDECL wined3d_volume_incref(struct wined3d_volume *volume)
115
{
116 117 118 119 120 121 122 123 124
    ULONG refcount;

    if (volume->container)
    {
        TRACE("Forwarding to container %p.\n", volume->container);
        return wined3d_texture_incref(volume->container);
    }

    refcount = InterlockedIncrement(&volume->resource.ref);
125

126
    TRACE("%p increasing refcount to %u.\n", volume, refcount);
127

128
    return refcount;
129 130
}

131
/* Do not call while under the GL lock. */
132 133
ULONG CDECL wined3d_volume_decref(struct wined3d_volume *volume)
{
134 135 136 137 138 139 140 141 142
    ULONG refcount;

    if (volume->container)
    {
        TRACE("Forwarding to container %p.\n", volume->container);
        return wined3d_texture_decref(volume->container);
    }

    refcount = InterlockedDecrement(&volume->resource.ref);
143 144

    TRACE("%p decreasing refcount to %u.\n", volume, refcount);
145

146
    if (!refcount)
147
    {
148 149 150
        resource_cleanup(&volume->resource);
        volume->resource.parent_ops->wined3d_object_destroyed(volume->resource.parent);
        HeapFree(GetProcessHeap(), 0, volume);
151
    }
152 153

    return refcount;
154 155
}

156
void * CDECL wined3d_volume_get_parent(const struct wined3d_volume *volume)
157
{
158
    TRACE("volume %p.\n", volume);
159

160
    return volume->resource.parent;
161 162
}

163
DWORD CDECL wined3d_volume_set_priority(struct wined3d_volume *volume, DWORD priority)
164
{
165
    return resource_set_priority(&volume->resource, priority);
166 167
}

168
DWORD CDECL wined3d_volume_get_priority(const struct wined3d_volume *volume)
169
{
170
    return resource_get_priority(&volume->resource);
171 172
}

173
/* Do not call while under the GL lock. */
174 175 176
void CDECL wined3d_volume_preload(struct wined3d_volume *volume)
{
    FIXME("volume %p stub!\n", volume);
177 178
}

179
struct wined3d_resource * CDECL wined3d_volume_get_resource(struct wined3d_volume *volume)
180
{
181
    TRACE("volume %p.\n", volume);
182

183
    return &volume->resource;
184 185
}

186
HRESULT CDECL wined3d_volume_map(struct wined3d_volume *volume,
187
        struct wined3d_map_desc *map_desc, const struct wined3d_box *box, DWORD flags)
188
{
189 190
    TRACE("volume %p, map_desc %p, box %p, flags %#x.\n",
            volume, map_desc, box, flags);
191

192 193
    if (!volume->resource.allocatedMemory)
        volume->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, volume->resource.size);
194

195
    TRACE("allocatedMemory %p.\n", volume->resource.allocatedMemory);
196

197 198
    map_desc->row_pitch = volume->resource.format->byte_count * volume->resource.width; /* Bytes / row */
    map_desc->slice_pitch = volume->resource.format->byte_count
199 200 201
            * volume->resource.width * volume->resource.height; /* Bytes / slice */
    if (!box)
    {
202
        TRACE("No box supplied - all is ok\n");
203
        map_desc->data = volume->resource.allocatedMemory;
204 205 206 207 208 209
        volume->lockedBox.left   = 0;
        volume->lockedBox.top    = 0;
        volume->lockedBox.front  = 0;
        volume->lockedBox.right  = volume->resource.width;
        volume->lockedBox.bottom = volume->resource.height;
        volume->lockedBox.back   = volume->resource.depth;
210 211 212
    }
    else
    {
213 214
        TRACE("Lock Box (%p) = l %u, t %u, r %u, b %u, fr %u, ba %u\n",
                box, box->left, box->top, box->right, box->bottom, box->front, box->back);
215 216 217
        map_desc->data = volume->resource.allocatedMemory
                + (map_desc->slice_pitch * box->front)     /* FIXME: is front < back or vica versa? */
                + (map_desc->row_pitch * box->top)
218 219 220 221 222 223 224
                + (box->left * volume->resource.format->byte_count);
        volume->lockedBox.left   = box->left;
        volume->lockedBox.top    = box->top;
        volume->lockedBox.front  = box->front;
        volume->lockedBox.right  = box->right;
        volume->lockedBox.bottom = box->bottom;
        volume->lockedBox.back   = box->back;
225
    }
226

227
    if (!(flags & (WINED3D_MAP_NO_DIRTY_UPDATE | WINED3D_MAP_READONLY)))
228
    {
229 230
        volume_add_dirty_box(volume, &volume->lockedBox);
        wined3d_texture_set_dirty(volume->container, TRUE);
231 232
    }

233 234 235
    volume->locked = TRUE;

    TRACE("Returning memory %p, row pitch %d, slice pitch %d.\n",
236
            map_desc->data, map_desc->row_pitch, map_desc->slice_pitch);
237

238
    return WINED3D_OK;
239 240
}

241
struct wined3d_volume * CDECL wined3d_volume_from_resource(struct wined3d_resource *resource)
242
{
243
    return volume_from_resource(resource);
244 245
}

246
HRESULT CDECL wined3d_volume_unmap(struct wined3d_volume *volume)
247
{
248 249 250
    TRACE("volume %p.\n", volume);

    if (!volume->locked)
251
    {
252
        WARN("Trying to unlock unlocked volume %p.\n", volume);
253
        return WINED3DERR_INVALIDCALL;
254
    }
255 256 257 258

    volume->locked = FALSE;
    memset(&volume->lockedBox, 0, sizeof(volume->lockedBox));

259
    return WINED3D_OK;
260 261
}

262 263 264 265 266
static const struct wined3d_resource_ops volume_resource_ops =
{
    volume_unload,
};

267
static HRESULT volume_init(struct wined3d_volume *volume, struct wined3d_device *device, UINT width,
268
        UINT height, UINT depth, DWORD usage, enum wined3d_format_id format_id, enum wined3d_pool pool,
269
        void *parent, const struct wined3d_parent_ops *parent_ops)
270 271
{
    const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
272
    const struct wined3d_format *format = wined3d_get_format(gl_info, format_id);
273 274 275 276 277 278 279 280
    HRESULT hr;

    if (!gl_info->supported[EXT_TEXTURE3D])
    {
        WARN("Volume cannot be created - no volume texture support.\n");
        return WINED3DERR_INVALIDCALL;
    }

281
    hr = resource_init(&volume->resource, device, WINED3D_RTYPE_VOLUME, format,
282
            WINED3D_MULTISAMPLE_NONE, 0, usage, pool, width, height, depth,
283 284
            width * height * depth * format->byte_count, parent, parent_ops,
            &volume_resource_ops);
285 286 287 288 289 290 291 292 293 294 295
    if (FAILED(hr))
    {
        WARN("Failed to initialize resource, returning %#x.\n", hr);
        return hr;
    }

    volume->lockable = TRUE;
    volume->locked = FALSE;
    memset(&volume->lockedBox, 0, sizeof(volume->lockedBox));
    volume->dirty = TRUE;

296
    volume_add_dirty_box(volume, NULL);
297 298 299

    return WINED3D_OK;
}
300

301
HRESULT CDECL wined3d_volume_create(struct wined3d_device *device, UINT width, UINT height,
302
        UINT depth, DWORD usage, enum wined3d_format_id format_id, enum wined3d_pool pool, void *parent,
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332
        const struct wined3d_parent_ops *parent_ops, struct wined3d_volume **volume)
{
    struct wined3d_volume *object;
    HRESULT hr;

    TRACE("device %p, width %u, height %u, depth %u, usage %#x, format %s, pool %s\n",
            device, width, height, depth, usage, debug_d3dformat(format_id), debug_d3dpool(pool));
    TRACE("parent %p, parent_ops %p, volume %p.\n", parent, parent_ops, volume);

    object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
    if (!object)
    {
        ERR("Out of memory\n");
        *volume = NULL;
        return WINED3DERR_OUTOFVIDEOMEMORY;
    }

    hr = volume_init(object, device, width, height, depth, usage, format_id, pool, parent, parent_ops);
    if (FAILED(hr))
    {
        WARN("Failed to initialize volume, returning %#x.\n", hr);
        HeapFree(GetProcessHeap(), 0, object);
        return hr;
    }

    TRACE("Created volume %p.\n", object);
    *volume = object;

    return WINED3D_OK;
}