texture.c 42.3 KB
Newer Older
1 2
/*
 * Copyright 2002-2005 Jason Edmeades
3 4
 * Copyright 2002-2005 Raphael Junqueira
 * Copyright 2005 Oliver Stieber
5
 * Copyright 2007-2009, 2013 Stefan Dösinger for CodeWeavers
6
 * Copyright 2009-2011 Henri Verbeet for CodeWeavers
7 8 9 10 11 12 13 14 15 16 17 18 19
 *
 * 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
20
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 22 23
 */

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

27
WINE_DEFAULT_DEBUG_CHANNEL(d3d_texture);
28

29
static HRESULT wined3d_texture_init(struct wined3d_texture *texture, const struct wined3d_texture_ops *texture_ops,
30
        UINT layer_count, UINT level_count, const struct wined3d_resource_desc *desc, struct wined3d_device *device,
31
        void *parent, const struct wined3d_parent_ops *parent_ops, const struct wined3d_resource_ops *resource_ops)
32
{
33
    const struct wined3d_format *format = wined3d_get_format(&device->adapter->gl_info, desc->format);
34 35
    HRESULT hr;

36 37 38 39 40 41 42 43
    TRACE("texture %p, texture_ops %p, layer_count %u, level_count %u, resource_type %s, format %s, "
            "multisample_type %#x, multisample_quality %#x, usage %s, pool %s, width %u, height %u, depth %u, "
            "device %p, parent %p, parent_ops %p, resource_ops %p.\n",
            texture, texture_ops, layer_count, level_count, debug_d3dresourcetype(desc->resource_type),
            debug_d3dformat(desc->format), desc->multisample_type, desc->multisample_quality,
            debug_d3dusage(desc->usage), debug_d3dpool(desc->pool), desc->width, desc->height, desc->depth,
            device, parent, parent_ops, resource_ops);

44 45 46 47 48 49 50 51
    if ((format->flags & (WINED3DFMT_FLAG_BLOCKS | WINED3DFMT_FLAG_BLOCKS_NO_VERIFY)) == WINED3DFMT_FLAG_BLOCKS)
    {
        UINT width_mask = format->block_width - 1;
        UINT height_mask = format->block_height - 1;
        if (desc->width & width_mask || desc->height & height_mask)
            return WINED3DERR_INVALIDCALL;
    }

52 53 54
    if (FAILED(hr = resource_init(&texture->resource, device, desc->resource_type, format,
            desc->multisample_type, desc->multisample_quality, desc->usage, desc->pool,
            desc->width, desc->height, desc->depth, 0, parent, parent_ops, resource_ops)))
55 56 57 58 59
    {
        WARN("Failed to initialize resource, returning %#x\n", hr);
        return hr;
    }

60 61 62 63
    texture->texture_ops = texture_ops;
    texture->sub_resources = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
            level_count * layer_count * sizeof(*texture->sub_resources));
    if (!texture->sub_resources)
64 65 66 67 68 69
    {
        ERR("Failed to allocate sub-resource array.\n");
        resource_cleanup(&texture->resource);
        return E_OUTOFMEMORY;
    }

70 71
    texture->layer_count = layer_count;
    texture->level_count = level_count;
72
    texture->filter_type = (desc->usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3D_TEXF_LINEAR : WINED3D_TEXF_NONE;
73
    texture->lod = 0;
74
    texture->flags = WINED3D_TEXTURE_POW2_MAT_IDENT;
75 76 77

    if (texture->resource.format->flags & WINED3DFMT_FLAG_FILTERING)
    {
78 79
        texture->min_mip_lookup = minMipLookup;
        texture->mag_lookup = magLookup;
80 81 82
    }
    else
    {
83 84
        texture->min_mip_lookup = minMipLookup_noFilter;
        texture->mag_lookup = magLookup_noFilter;
85 86 87 88 89 90
    }

    return WINED3D_OK;
}

/* A GL context is provided by the caller */
91
static void gltexture_delete(const struct wined3d_gl_info *gl_info, struct gl_texture *tex)
92
{
93
    gl_info->gl_ops.gl.p_glDeleteTextures(1, &tex->name);
94 95 96
    tex->name = 0;
}

97
static void wined3d_texture_unload_gl_texture(struct wined3d_texture *texture)
98
{
99
    struct wined3d_device *device = texture->resource.device;
100 101
    struct wined3d_context *context = NULL;

102
    if (texture->texture_rgb.name || texture->texture_srgb.name)
103 104 105 106
    {
        context = context_acquire(device, NULL);
    }

107
    if (texture->texture_rgb.name)
108
        gltexture_delete(context->gl_info, &texture->texture_rgb);
109

110
    if (texture->texture_srgb.name)
111
        gltexture_delete(context->gl_info, &texture->texture_srgb);
112 113 114

    if (context) context_release(context);

115
    wined3d_texture_set_dirty(texture);
116 117 118 119

    resource_unload(&texture->resource);
}

120
static void wined3d_texture_cleanup(struct wined3d_texture *texture)
121
{
122
    UINT sub_count = texture->level_count * texture->layer_count;
123 124 125 126 127 128
    UINT i;

    TRACE("texture %p.\n", texture);

    for (i = 0; i < sub_count; ++i)
    {
129
        struct wined3d_resource *sub_resource = texture->sub_resources[i];
130 131

        if (sub_resource)
132
            texture->texture_ops->texture_sub_resource_cleanup(sub_resource);
133 134
    }

135
    wined3d_texture_unload_gl_texture(texture);
136
    HeapFree(GetProcessHeap(), 0, texture->sub_resources);
137 138 139
    resource_cleanup(&texture->resource);
}

140
void wined3d_texture_set_dirty(struct wined3d_texture *texture)
141
{
142
    texture->flags &= ~(WINED3D_TEXTURE_RGB_VALID | WINED3D_TEXTURE_SRGB_VALID);
143 144
}

145
/* Context activation is done by the caller. */
146 147
void wined3d_texture_bind(struct wined3d_texture *texture,
        struct wined3d_context *context, BOOL srgb)
148
{
149
    const struct wined3d_gl_info *gl_info = context->gl_info;
150 151 152
    struct gl_texture *gl_tex;
    GLenum target;

153
    TRACE("texture %p, context %p, srgb %#x.\n", texture, context, srgb);
154

155 156 157
    if (gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
        srgb = FALSE;

158 159 160 161 162 163
    /* sRGB mode cache for preload() calls outside drawprim. */
    if (srgb)
        texture->flags |= WINED3D_TEXTURE_IS_SRGB;
    else
        texture->flags &= ~WINED3D_TEXTURE_IS_SRGB;

164
    gl_tex = wined3d_texture_get_gl_texture(texture, srgb);
165
    target = texture->target;
166

167 168 169 170 171 172 173 174 175 176
    if (gl_tex->name)
    {
        context_bind_texture(context, target, gl_tex->name);
        return;
    }

    gl_info->gl_ops.gl.p_glGenTextures(1, &gl_tex->name);
    checkGLcall("glGenTextures");
    TRACE("Generated texture %d.\n", gl_tex->name);

177 178
    if (!gl_tex->name)
    {
179 180
        ERR("Failed to generate a texture name.\n");
        return;
181 182
    }

183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
    if (texture->resource.pool == WINED3D_POOL_DEFAULT)
    {
        /* Tell OpenGL to try and keep this texture in video ram (well mostly). */
        GLclampf tmp = 0.9f;
        gl_info->gl_ops.gl.p_glPrioritizeTextures(1, &gl_tex->name, &tmp);
    }

    /* Initialise the state of the texture object to the OpenGL defaults, not
     * the wined3d defaults. */
    gl_tex->states[WINED3DTEXSTA_ADDRESSU] = WINED3D_TADDRESS_WRAP;
    gl_tex->states[WINED3DTEXSTA_ADDRESSV] = WINED3D_TADDRESS_WRAP;
    gl_tex->states[WINED3DTEXSTA_ADDRESSW] = WINED3D_TADDRESS_WRAP;
    gl_tex->states[WINED3DTEXSTA_BORDERCOLOR] = 0;
    gl_tex->states[WINED3DTEXSTA_MAGFILTER] = WINED3D_TEXF_LINEAR;
    gl_tex->states[WINED3DTEXSTA_MINFILTER] = WINED3D_TEXF_POINT; /* GL_NEAREST_MIPMAP_LINEAR */
    gl_tex->states[WINED3DTEXSTA_MIPFILTER] = WINED3D_TEXF_LINEAR; /* GL_NEAREST_MIPMAP_LINEAR */
    gl_tex->states[WINED3DTEXSTA_MAXMIPLEVEL] = 0;
    gl_tex->states[WINED3DTEXSTA_MAXANISOTROPY] = 1;
    if (context->gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
        gl_tex->states[WINED3DTEXSTA_SRGBTEXTURE] = TRUE;
    else
        gl_tex->states[WINED3DTEXSTA_SRGBTEXTURE] = srgb;
    gl_tex->states[WINED3DTEXSTA_SHADOW] = FALSE;
    wined3d_texture_set_dirty(texture);

208
    context_bind_texture(context, target, gl_tex->name);
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237

    if (texture->resource.usage & WINED3DUSAGE_AUTOGENMIPMAP)
    {
        gl_info->gl_ops.gl.p_glTexParameteri(target, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
        checkGLcall("glTexParameteri(target, GL_GENERATE_MIPMAP_SGIS, GL_TRUE)");
    }

    /* For a new texture we have to set the texture levels after binding the
     * texture. Beware that texture rectangles do not support mipmapping, but
     * set the maxmiplevel if we're relying on the partial
     * GL_ARB_texture_non_power_of_two emulation with texture rectangles.
     * (I.e., do not care about cond_np2 here, just look for
     * GL_TEXTURE_RECTANGLE_ARB.) */
    if (target != GL_TEXTURE_RECTANGLE_ARB)
    {
        TRACE("Setting GL_TEXTURE_MAX_LEVEL to %u.\n", texture->level_count - 1);
        gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, texture->level_count - 1);
        checkGLcall("glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, texture->level_count)");
    }

    if (target == GL_TEXTURE_CUBE_MAP_ARB)
    {
        /* Cubemaps are always set to clamp, regardless of the sampler state. */
        gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
    }

    if (texture->flags & WINED3D_TEXTURE_COND_NP2)
238
    {
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
        /* Conditinal non power of two textures use a different clamping
         * default. If we're using the GL_WINE_normalized_texrect partial
         * driver emulation, we're dealing with a GL_TEXTURE_2D texture which
         * has the address mode set to repeat - something that prevents us
         * from hitting the accelerated codepath. Thus manually set the GL
         * state. The same applies to filtering. Even if the texture has only
         * one mip level, the default LINEAR_MIPMAP_LINEAR filter causes a SW
         * fallback on macos. */
        gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        checkGLcall("glTexParameteri");
        gl_tex->states[WINED3DTEXSTA_ADDRESSU] = WINED3D_TADDRESS_CLAMP;
        gl_tex->states[WINED3DTEXSTA_ADDRESSV] = WINED3D_TADDRESS_CLAMP;
        gl_tex->states[WINED3DTEXSTA_MAGFILTER] = WINED3D_TEXF_POINT;
        gl_tex->states[WINED3DTEXSTA_MINFILTER] = WINED3D_TEXF_POINT;
        gl_tex->states[WINED3DTEXSTA_MIPFILTER] = WINED3D_TEXF_NONE;
257 258 259
    }
}

260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281
/* Context activation is done by the caller. */
void wined3d_texture_bind_and_dirtify(struct wined3d_texture *texture,
        struct wined3d_context *context, BOOL srgb)
{
    DWORD active_sampler;

    /* 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 marking already applied sampler states dirty again. */
    active_sampler = context->rev_tex_unit_map[context->active_texture];
    if (active_sampler != WINED3D_UNMAPPED_STAGE)
        context_invalidate_state(context, STATE_SAMPLER(active_sampler));

    wined3d_texture_bind(texture, context, srgb);
}

282
/* Context activation is done by the caller. */
283
static void apply_wrap(const struct wined3d_gl_info *gl_info, GLenum target,
284
        enum wined3d_texture_address d3d_wrap, GLenum param, BOOL cond_np2)
285 286 287
{
    GLint gl_wrap;

288
    if (d3d_wrap < WINED3D_TADDRESS_WRAP || d3d_wrap > WINED3D_TADDRESS_MIRROR_ONCE)
289
    {
290
        FIXME("Unrecognized or unsupported texture address mode %#x.\n", d3d_wrap);
291 292 293 294 295
        return;
    }

    /* Cubemaps are always set to clamp, regardless of the sampler state. */
    if (target == GL_TEXTURE_CUBE_MAP_ARB
296
            || (cond_np2 && d3d_wrap == WINED3D_TADDRESS_WRAP))
297 298
        gl_wrap = GL_CLAMP_TO_EDGE;
    else
299
        gl_wrap = gl_info->wrap_lookup[d3d_wrap - WINED3D_TADDRESS_WRAP];
300 301

    TRACE("Setting param %#x to %#x for target %#x.\n", param, gl_wrap, target);
302
    gl_info->gl_ops.gl.p_glTexParameteri(target, param, gl_wrap);
303 304 305
    checkGLcall("glTexParameteri(target, param, gl_wrap)");
}

306
/* Context activation is done by the caller (state handler). */
307
void wined3d_texture_apply_state_changes(struct wined3d_texture *texture,
308 309 310
        const DWORD sampler_states[WINED3D_HIGHEST_SAMPLER_STATE + 1],
        const struct wined3d_gl_info *gl_info)
{
311
    BOOL cond_np2 = texture->flags & WINED3D_TEXTURE_COND_NP2;
312
    GLenum target = texture->target;
313 314 315 316 317 318
    struct gl_texture *gl_tex;
    DWORD state;
    DWORD aniso;

    TRACE("texture %p, sampler_states %p.\n", texture, sampler_states);

319
    gl_tex = wined3d_texture_get_gl_texture(texture, texture->flags & WINED3D_TEXTURE_IS_SRGB);
320 321 322

    /* This function relies on the correct texture being bound and loaded. */

323
    if (sampler_states[WINED3D_SAMP_ADDRESS_U] != gl_tex->states[WINED3DTEXSTA_ADDRESSU])
324
    {
325
        state = sampler_states[WINED3D_SAMP_ADDRESS_U];
326 327 328 329
        apply_wrap(gl_info, target, state, GL_TEXTURE_WRAP_S, cond_np2);
        gl_tex->states[WINED3DTEXSTA_ADDRESSU] = state;
    }

330
    if (sampler_states[WINED3D_SAMP_ADDRESS_V] != gl_tex->states[WINED3DTEXSTA_ADDRESSV])
331
    {
332
        state = sampler_states[WINED3D_SAMP_ADDRESS_V];
333 334 335 336
        apply_wrap(gl_info, target, state, GL_TEXTURE_WRAP_T, cond_np2);
        gl_tex->states[WINED3DTEXSTA_ADDRESSV] = state;
    }

337
    if (sampler_states[WINED3D_SAMP_ADDRESS_W] != gl_tex->states[WINED3DTEXSTA_ADDRESSW])
338
    {
339
        state = sampler_states[WINED3D_SAMP_ADDRESS_W];
340 341 342 343
        apply_wrap(gl_info, target, state, GL_TEXTURE_WRAP_R, cond_np2);
        gl_tex->states[WINED3DTEXSTA_ADDRESSW] = state;
    }

344
    if (sampler_states[WINED3D_SAMP_BORDER_COLOR] != gl_tex->states[WINED3DTEXSTA_BORDERCOLOR])
345 346 347
    {
        float col[4];

348
        state = sampler_states[WINED3D_SAMP_BORDER_COLOR];
349 350
        D3DCOLORTOGLFLOAT4(state, col);
        TRACE("Setting border color for %#x to %#x.\n", target, state);
351
        gl_info->gl_ops.gl.p_glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, &col[0]);
352 353 354 355
        checkGLcall("glTexParameterfv(..., GL_TEXTURE_BORDER_COLOR, ...)");
        gl_tex->states[WINED3DTEXSTA_BORDERCOLOR] = state;
    }

356
    if (sampler_states[WINED3D_SAMP_MAG_FILTER] != gl_tex->states[WINED3DTEXSTA_MAGFILTER])
357 358 359
    {
        GLint gl_value;

360
        state = sampler_states[WINED3D_SAMP_MAG_FILTER];
361
        if (state > WINED3D_TEXF_ANISOTROPIC)
362 363
            FIXME("Unrecognized or unsupported MAGFILTER* value %d.\n", state);

364
        gl_value = wined3d_gl_mag_filter(texture->mag_lookup,
365
                min(max(state, WINED3D_TEXF_POINT), WINED3D_TEXF_LINEAR));
366
        TRACE("ValueMAG=%#x setting MAGFILTER to %#x.\n", state, gl_value);
367
        gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MAG_FILTER, gl_value);
368 369 370 371

        gl_tex->states[WINED3DTEXSTA_MAGFILTER] = state;
    }

372 373 374
    if ((sampler_states[WINED3D_SAMP_MIN_FILTER] != gl_tex->states[WINED3DTEXSTA_MINFILTER]
            || sampler_states[WINED3D_SAMP_MIP_FILTER] != gl_tex->states[WINED3DTEXSTA_MIPFILTER]
            || sampler_states[WINED3D_SAMP_MAX_MIP_LEVEL] != gl_tex->states[WINED3DTEXSTA_MAXMIPLEVEL]))
375 376 377
    {
        GLint gl_value;

378 379 380
        gl_tex->states[WINED3DTEXSTA_MIPFILTER] = sampler_states[WINED3D_SAMP_MIP_FILTER];
        gl_tex->states[WINED3DTEXSTA_MINFILTER] = sampler_states[WINED3D_SAMP_MIN_FILTER];
        gl_tex->states[WINED3DTEXSTA_MAXMIPLEVEL] = sampler_states[WINED3D_SAMP_MAX_MIP_LEVEL];
381

382 383
        if (gl_tex->states[WINED3DTEXSTA_MINFILTER] > WINED3D_TEXF_ANISOTROPIC
            || gl_tex->states[WINED3DTEXSTA_MIPFILTER] > WINED3D_TEXF_ANISOTROPIC)
384
        {
385
            FIXME("Unrecognized or unsupported MIN_FILTER value %#x MIP_FILTER value %#x.\n",
386 387 388
                  gl_tex->states[WINED3DTEXSTA_MINFILTER],
                  gl_tex->states[WINED3DTEXSTA_MIPFILTER]);
        }
389
        gl_value = wined3d_gl_min_mip_filter(texture->min_mip_lookup,
390 391
                min(max(sampler_states[WINED3D_SAMP_MIN_FILTER], WINED3D_TEXF_POINT), WINED3D_TEXF_LINEAR),
                min(max(sampler_states[WINED3D_SAMP_MIP_FILTER], WINED3D_TEXF_NONE), WINED3D_TEXF_LINEAR));
392 393

        TRACE("ValueMIN=%#x, ValueMIP=%#x, setting MINFILTER to %#x.\n",
394 395
              sampler_states[WINED3D_SAMP_MIN_FILTER],
              sampler_states[WINED3D_SAMP_MIP_FILTER], gl_value);
396
        gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MIN_FILTER, gl_value);
397 398 399 400
        checkGLcall("glTexParameter GL_TEXTURE_MIN_FILTER, ...");

        if (!cond_np2)
        {
401
            if (gl_tex->states[WINED3DTEXSTA_MIPFILTER] == WINED3D_TEXF_NONE)
402 403 404 405 406 407
                gl_value = texture->lod;
            else if (gl_tex->states[WINED3DTEXSTA_MAXMIPLEVEL] >= texture->level_count)
                gl_value = texture->level_count - 1;
            else if (gl_tex->states[WINED3DTEXSTA_MAXMIPLEVEL] < texture->lod)
                /* texture->lod is already clamped in the setter. */
                gl_value = texture->lod;
408 409 410
            else
                gl_value = gl_tex->states[WINED3DTEXSTA_MAXMIPLEVEL];

411
            /* Note that WINED3D_SAMP_MAX_MIP_LEVEL specifies the largest mipmap
412
             * (default 0), while GL_TEXTURE_MAX_LEVEL specifies the smallest
413
             * mimap used (default 1000). So WINED3D_SAMP_MAX_MIP_LEVEL
414
             * corresponds to GL_TEXTURE_BASE_LEVEL. */
415
            gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_BASE_LEVEL, gl_value);
416 417 418
        }
    }

419 420 421
    if ((gl_tex->states[WINED3DTEXSTA_MAGFILTER] != WINED3D_TEXF_ANISOTROPIC
            && gl_tex->states[WINED3DTEXSTA_MINFILTER] != WINED3D_TEXF_ANISOTROPIC
            && gl_tex->states[WINED3DTEXSTA_MIPFILTER] != WINED3D_TEXF_ANISOTROPIC)
422 423 424
            || cond_np2)
        aniso = 1;
    else
425
        aniso = sampler_states[WINED3D_SAMP_MAX_ANISOTROPY];
426 427 428 429 430

    if (gl_tex->states[WINED3DTEXSTA_MAXANISOTROPY] != aniso)
    {
        if (gl_info->supported[EXT_TEXTURE_FILTER_ANISOTROPIC])
        {
431
            gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);
432 433 434 435 436 437 438 439 440 441
            checkGLcall("glTexParameteri(GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso)");
        }
        else
        {
            WARN("Anisotropic filtering not supported.\n");
        }
        gl_tex->states[WINED3DTEXSTA_MAXANISOTROPY] = aniso;
    }

    /* These should always be the same unless EXT_texture_sRGB_decode is supported. */
442
    if (sampler_states[WINED3D_SAMP_SRGB_TEXTURE] != gl_tex->states[WINED3DTEXSTA_SRGBTEXTURE])
443
    {
444
        gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_SRGB_DECODE_EXT,
445
                sampler_states[WINED3D_SAMP_SRGB_TEXTURE] ? GL_DECODE_EXT : GL_SKIP_DECODE_EXT);
446
        checkGLcall("glTexParameteri(GL_TEXTURE_SRGB_DECODE_EXT)");
447
        gl_tex->states[WINED3DTEXSTA_SRGBTEXTURE] = sampler_states[WINED3D_SAMP_SRGB_TEXTURE];
448 449 450 451 452 453 454
    }

    if (!(texture->resource.format->flags & WINED3DFMT_FLAG_SHADOW)
            != !gl_tex->states[WINED3DTEXSTA_SHADOW])
    {
        if (texture->resource.format->flags & WINED3DFMT_FLAG_SHADOW)
        {
455 456
            gl_info->gl_ops.gl.p_glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
            gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
457 458 459 460 461
            checkGLcall("glTexParameteri(target, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB)");
            gl_tex->states[WINED3DTEXSTA_SHADOW] = TRUE;
        }
        else
        {
462
            gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
463 464 465 466 467 468
            checkGLcall("glTexParameteri(target, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE)");
            gl_tex->states[WINED3DTEXSTA_SHADOW] = FALSE;
        }
    }
}

469
ULONG CDECL wined3d_texture_incref(struct wined3d_texture *texture)
470 471 472 473 474 475 476 477
{
    ULONG refcount = InterlockedIncrement(&texture->resource.ref);

    TRACE("%p increasing refcount to %u.\n", texture, refcount);

    return refcount;
}

478
ULONG CDECL wined3d_texture_decref(struct wined3d_texture *texture)
479 480 481 482 483 484 485
{
    ULONG refcount = InterlockedDecrement(&texture->resource.ref);

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

    if (!refcount)
    {
486
        wined3d_texture_cleanup(texture);
487 488 489 490 491 492 493
        texture->resource.parent_ops->wined3d_object_destroyed(texture->resource.parent);
        HeapFree(GetProcessHeap(), 0, texture);
    }

    return refcount;
}

494 495 496 497 498 499 500
struct wined3d_resource * CDECL wined3d_texture_get_resource(struct wined3d_texture *texture)
{
    TRACE("texture %p.\n", texture);

    return &texture->resource;
}

501
DWORD CDECL wined3d_texture_set_priority(struct wined3d_texture *texture, DWORD priority)
502
{
503
    return resource_set_priority(&texture->resource, priority);
504 505
}

506
DWORD CDECL wined3d_texture_get_priority(const struct wined3d_texture *texture)
507
{
508
    return resource_get_priority(&texture->resource);
509 510
}

511 512
/* Context activation is done by the caller */
void wined3d_texture_load(struct wined3d_texture *texture,
513
        struct wined3d_context *context, BOOL srgb)
514 515 516 517 518 519 520 521 522
{
    UINT sub_count = texture->level_count * texture->layer_count;
    const struct wined3d_gl_info *gl_info = context->gl_info;
    DWORD flag;
    UINT i;

    TRACE("texture %p, srgb %#x.\n", texture, srgb);

    if (gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
523
        srgb = FALSE;
524

525
    if (srgb)
526 527 528 529 530 531 532 533 534 535 536 537 538
        flag = WINED3D_TEXTURE_SRGB_VALID;
    else
        flag = WINED3D_TEXTURE_RGB_VALID;

    if (texture->flags & flag)
    {
        TRACE("Texture %p not dirty, nothing to do.\n", texture);
        return;
    }

    /* Reload the surfaces if the texture is marked dirty. */
    for (i = 0; i < sub_count; ++i)
    {
539
        texture->texture_ops->texture_sub_resource_load(texture->sub_resources[i], context, srgb);
540 541 542 543
    }
    texture->flags |= flag;
}

544
void CDECL wined3d_texture_preload(struct wined3d_texture *texture)
545
{
546 547
    struct wined3d_context *context;
    context = context_acquire(texture->resource.device, NULL);
548
    wined3d_texture_load(texture, context, texture->flags & WINED3D_TEXTURE_IS_SRGB);
549
    context_release(context);
550 551
}

552
void * CDECL wined3d_texture_get_parent(const struct wined3d_texture *texture)
553
{
554
    TRACE("texture %p.\n", texture);
555

556
    return texture->resource.parent;
557 558
}

559
DWORD CDECL wined3d_texture_set_lod(struct wined3d_texture *texture, DWORD lod)
560
{
561
    DWORD old = texture->lod;
562

563
    TRACE("texture %p, lod %u.\n", texture, lod);
564 565 566

    /* The d3d9:texture test shows that SetLOD is ignored on non-managed
     * textures. The call always returns 0, and GetLOD always returns 0. */
567
    if (texture->resource.pool != WINED3D_POOL_MANAGED)
568 569 570 571 572
    {
        TRACE("Ignoring SetLOD on %s texture, returning 0.\n", debug_d3dpool(texture->resource.pool));
        return 0;
    }

573 574
    if (lod >= texture->level_count)
        lod = texture->level_count - 1;
575

576
    if (texture->lod != lod)
577
    {
578
        texture->lod = lod;
579

580 581
        texture->texture_rgb.states[WINED3DTEXSTA_MAXMIPLEVEL] = ~0U;
        texture->texture_srgb.states[WINED3DTEXSTA_MAXMIPLEVEL] = ~0U;
582
        if (texture->resource.bind_count)
583
            device_invalidate_state(texture->resource.device, STATE_SAMPLER(texture->sampler));
584 585 586 587 588
    }

    return old;
}

589
DWORD CDECL wined3d_texture_get_lod(const struct wined3d_texture *texture)
590
{
591
    TRACE("texture %p, returning %u.\n", texture, texture->lod);
592

593
    return texture->lod;
594 595
}

596
DWORD CDECL wined3d_texture_get_level_count(const struct wined3d_texture *texture)
597
{
598
    TRACE("texture %p, returning %u.\n", texture, texture->level_count);
599

600
    return texture->level_count;
601 602
}

603
HRESULT CDECL wined3d_texture_set_autogen_filter_type(struct wined3d_texture *texture,
604
        enum wined3d_texture_filter_type filter_type)
605
{
606
    FIXME("texture %p, filter_type %s stub!\n", texture, debug_d3dtexturefiltertype(filter_type));
607 608 609 610 611 612 613

    if (!(texture->resource.usage & WINED3DUSAGE_AUTOGENMIPMAP))
    {
        WARN("Texture doesn't have AUTOGENMIPMAP usage.\n");
        return WINED3DERR_INVALIDCALL;
    }

614
    texture->filter_type = filter_type;
615 616 617 618

    return WINED3D_OK;
}

619
enum wined3d_texture_filter_type CDECL wined3d_texture_get_autogen_filter_type(const struct wined3d_texture *texture)
620
{
621
    TRACE("texture %p.\n", texture);
622

623
    return texture->filter_type;
624 625
}

626
void CDECL wined3d_texture_generate_mipmaps(struct wined3d_texture *texture)
627 628
{
    /* TODO: Implement filters using GL_SGI_generate_mipmaps. */
629
    FIXME("texture %p stub!\n", texture);
630 631
}

632
struct wined3d_resource * CDECL wined3d_texture_get_sub_resource(struct wined3d_texture *texture,
633 634
        UINT sub_resource_idx)
{
635
    UINT sub_count = texture->level_count * texture->layer_count;
636 637 638 639 640 641 642 643

    TRACE("texture %p, sub_resource_idx %u.\n", texture, sub_resource_idx);

    if (sub_resource_idx >= sub_count)
    {
        WARN("sub_resource_idx %u >= sub_count %u.\n", sub_resource_idx, sub_count);
        return NULL;
    }
644

645
    return texture->sub_resources[sub_resource_idx];
646 647
}

648
HRESULT CDECL wined3d_texture_add_dirty_region(struct wined3d_texture *texture,
649
        UINT layer, const struct wined3d_box *dirty_region)
650 651 652 653 654
{
    struct wined3d_resource *sub_resource;

    TRACE("texture %p, layer %u, dirty_region %p.\n", texture, layer, dirty_region);

655
    if (!(sub_resource = wined3d_texture_get_sub_resource(texture, layer * texture->level_count)))
656 657 658 659 660
    {
        WARN("Failed to get sub-resource.\n");
        return WINED3DERR_INVALIDCALL;
    }

661
    texture->texture_ops->texture_sub_resource_add_dirty_region(sub_resource, dirty_region);
662 663 664 665

    return WINED3D_OK;
}

666 667
static void texture2d_sub_resource_load(struct wined3d_resource *sub_resource,
        struct wined3d_context *context, BOOL srgb)
668
{
669
    surface_load(surface_from_resource(sub_resource), srgb);
670
}
671

672
static void texture2d_sub_resource_add_dirty_region(struct wined3d_resource *sub_resource,
673
        const struct wined3d_box *dirty_region)
674
{
675 676 677 678
    struct wined3d_surface *surface = surface_from_resource(sub_resource);

    surface_load_location(surface, SFLAG_INSYSMEM);
    surface_invalidate_location(surface, ~SFLAG_INSYSMEM);
679 680
}

681
static void texture2d_sub_resource_cleanup(struct wined3d_resource *sub_resource)
682
{
683
    struct wined3d_surface *surface = surface_from_resource(sub_resource);
684

685
    surface_set_texture_target(surface, 0, 0);
686
    surface_set_container(surface, NULL);
687
    wined3d_surface_decref(surface);
688 689
}

690 691
static const struct wined3d_texture_ops texture2d_ops =
{
692
    texture2d_sub_resource_load,
693 694 695 696 697
    texture2d_sub_resource_add_dirty_region,
    texture2d_sub_resource_cleanup,
};

static void wined3d_texture_unload(struct wined3d_resource *resource)
698
{
699
    struct wined3d_texture *texture = wined3d_texture_from_resource(resource);
700
    UINT sub_count = texture->level_count * texture->layer_count;
701
    UINT i;
702 703 704

    TRACE("texture %p.\n", texture);

705
    for (i = 0; i < sub_count; ++i)
706
    {
707
        struct wined3d_resource *sub_resource = texture->sub_resources[i];
708

709
        sub_resource->resource_ops->resource_unload(sub_resource);
710 711
    }

712
    wined3d_texture_unload_gl_texture(texture);
713 714
}

715
static const struct wined3d_resource_ops texture_resource_ops =
716
{
717
    wined3d_texture_unload,
718
};
719

720
static HRESULT cubetexture_init(struct wined3d_texture *texture, const struct wined3d_resource_desc *desc,
721 722
        UINT levels, DWORD surface_flags, struct wined3d_device *device, void *parent,
        const struct wined3d_parent_ops *parent_ops)
723
{
724
    const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
725
    struct wined3d_resource_desc surface_desc;
726 727
    unsigned int i, j;
    HRESULT hr;
728

729 730
    /* TODO: It should only be possible to create textures for formats
     * that are reported as supported. */
731
    if (WINED3DFMT_UNKNOWN >= desc->format)
732 733 734 735
    {
        WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN.\n", texture);
        return WINED3DERR_INVALIDCALL;
    }
736

737
    if (!gl_info->supported[ARB_TEXTURE_CUBE_MAP] && desc->pool != WINED3D_POOL_SCRATCH)
738 739 740 741
    {
        WARN("(%p) : Tried to create not supported cube texture.\n", texture);
        return WINED3DERR_INVALIDCALL;
    }
742

743
    /* Calculate levels for mip mapping */
744
    if (desc->usage & WINED3DUSAGE_AUTOGENMIPMAP)
745 746 747 748 749 750
    {
        if (!gl_info->supported[SGIS_GENERATE_MIPMAP])
        {
            WARN("No mipmap generation support, returning D3DERR_INVALIDCALL.\n");
            return WINED3DERR_INVALIDCALL;
        }
751

752 753 754 755 756
        if (levels > 1)
        {
            WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL.\n");
            return WINED3DERR_INVALIDCALL;
        }
757

758 759 760 761
        levels = 1;
    }
    else if (!levels)
    {
762
        levels = wined3d_log2i(desc->width) + 1;
763 764
        TRACE("Calculated levels = %u.\n", levels);
    }
765

766 767 768
    if (!gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO])
    {
        UINT pow2_edge_length = 1;
769 770
        while (pow2_edge_length < desc->width)
            pow2_edge_length <<= 1;
771

772
        if (desc->width != pow2_edge_length)
773
        {
774
            if (desc->pool == WINED3D_POOL_SCRATCH)
775 776 777 778 779 780
            {
                /* SCRATCH textures cannot be used for texturing */
                WARN("Creating a scratch NPOT cube texture despite lack of HW support.\n");
            }
            else
            {
781
                WARN("Attempted to create a NPOT cube texture (edge length %u) without GL support.\n", desc->width);
782 783 784 785 786
                return WINED3DERR_INVALIDCALL;
            }
        }
    }

787
    if (FAILED(hr = wined3d_texture_init(texture, &texture2d_ops, 6, levels,
788
            desc, device, parent, parent_ops, &texture_resource_ops)))
789
    {
790
        WARN("Failed to initialize texture, returning %#x\n", hr);
791 792
        return hr;
    }
793

794 795 796 797
    texture->pow2_matrix[0] = 1.0f;
    texture->pow2_matrix[5] = 1.0f;
    texture->pow2_matrix[10] = 1.0f;
    texture->pow2_matrix[15] = 1.0f;
798
    texture->target = GL_TEXTURE_CUBE_MAP_ARB;
799

800
    /* Generate all the surfaces. */
801 802
    surface_desc = *desc;
    surface_desc.resource_type = WINED3D_RTYPE_SURFACE;
803
    for (i = 0; i < texture->level_count; ++i)
804 805 806 807 808 809 810 811 812 813 814 815 816
    {
        /* Create the 6 faces. */
        for (j = 0; j < 6; ++j)
        {
            static const GLenum cube_targets[6] =
            {
                GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
                GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
                GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
                GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
                GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
                GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB,
            };
817
            UINT idx = j * texture->level_count + i;
818
            struct wined3d_surface *surface;
819

820
            if (FAILED(hr = wined3d_surface_create(texture, &surface_desc, surface_flags, &surface)))
821
            {
822
                WARN("Failed to create surface, hr %#x.\n", hr);
823
                wined3d_texture_cleanup(texture);
824 825
                return hr;
            }
826

827
            surface_set_texture_target(surface, cube_targets[j], i);
828
            texture->sub_resources[idx] = &surface->resource;
829 830
            TRACE("Created surface level %u @ %p.\n", i, surface);
        }
831 832
        surface_desc.width = max(1, surface_desc.width >> 1);
        surface_desc.height = surface_desc.width;
833
    }
834

835
    return WINED3D_OK;
836 837
}

838
static HRESULT texture_init(struct wined3d_texture *texture, const struct wined3d_resource_desc *desc,
839 840
        UINT levels, DWORD surface_flags, struct wined3d_device *device, void *parent,
        const struct wined3d_parent_ops *parent_ops)
841 842
{
    const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
843
    struct wined3d_resource_desc surface_desc;
844 845 846 847 848 849
    UINT pow2_width, pow2_height;
    unsigned int i;
    HRESULT hr;

    /* TODO: It should only be possible to create textures for formats
     * that are reported as supported. */
850
    if (WINED3DFMT_UNKNOWN >= desc->format)
851 852 853 854 855 856 857 858
    {
        WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN.\n", texture);
        return WINED3DERR_INVALIDCALL;
    }

    /* Non-power2 support. */
    if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO])
    {
859 860
        pow2_width = desc->width;
        pow2_height = desc->height;
861 862 863 864 865
    }
    else
    {
        /* Find the nearest pow2 match. */
        pow2_width = pow2_height = 1;
866 867 868 869
        while (pow2_width < desc->width)
            pow2_width <<= 1;
        while (pow2_height < desc->height)
            pow2_height <<= 1;
870

871
        if (pow2_width != desc->width || pow2_height != desc->height)
872
        {
873 874
            /* levels == 0 returns an error as well */
            if (levels != 1)
875
            {
876
                if (desc->pool == WINED3D_POOL_SCRATCH)
877 878 879 880 881 882 883 884
                {
                    WARN("Creating a scratch mipmapped NPOT texture despite lack of HW support.\n");
                }
                else
                {
                    WARN("Attempted to create a mipmapped NPOT texture without unconditional NPOT support.\n");
                    return WINED3DERR_INVALIDCALL;
                }
885 886 887 888 889
            }
        }
    }

    /* Calculate levels for mip mapping. */
890
    if (desc->usage & WINED3DUSAGE_AUTOGENMIPMAP)
891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907
    {
        if (!gl_info->supported[SGIS_GENERATE_MIPMAP])
        {
            WARN("No mipmap generation support, returning WINED3DERR_INVALIDCALL.\n");
            return WINED3DERR_INVALIDCALL;
        }

        if (levels > 1)
        {
            WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning WINED3DERR_INVALIDCALL.\n");
            return WINED3DERR_INVALIDCALL;
        }

        levels = 1;
    }
    else if (!levels)
    {
908
        levels = wined3d_log2i(max(desc->width, desc->height)) + 1;
909 910 911
        TRACE("Calculated levels = %u.\n", levels);
    }

912
    if (FAILED(hr = wined3d_texture_init(texture, &texture2d_ops, 1, levels,
913
            desc, device, parent, parent_ops, &texture_resource_ops)))
914
    {
915
        WARN("Failed to initialize texture, returning %#x.\n", hr);
916 917 918
        return hr;
    }

919
    /* Precalculated scaling for 'faked' non power of two texture coords. */
920 921
    if (gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT]
            && (desc->width != pow2_width || desc->height != pow2_height))
922
    {
923 924 925 926 927
        texture->pow2_matrix[0] = 1.0f;
        texture->pow2_matrix[5] = 1.0f;
        texture->pow2_matrix[10] = 1.0f;
        texture->pow2_matrix[15] = 1.0f;
        texture->target = GL_TEXTURE_2D;
928
        texture->flags |= WINED3D_TEXTURE_COND_NP2;
929
        texture->min_mip_lookup = minMipLookup_noFilter;
930
    }
931 932
    else if (gl_info->supported[ARB_TEXTURE_RECTANGLE]
            && (desc->width != pow2_width || desc->height != pow2_height))
933
    {
934 935
        texture->pow2_matrix[0] = (float)desc->width;
        texture->pow2_matrix[5] = (float)desc->height;
936 937 938
        texture->pow2_matrix[10] = 1.0f;
        texture->pow2_matrix[15] = 1.0f;
        texture->target = GL_TEXTURE_RECTANGLE_ARB;
939
        texture->flags |= WINED3D_TEXTURE_COND_NP2;
940
        texture->flags &= ~WINED3D_TEXTURE_POW2_MAT_IDENT;
941

942
        if (texture->resource.format->flags & WINED3DFMT_FLAG_FILTERING)
943
            texture->min_mip_lookup = minMipLookup_noMip;
944
        else
945
            texture->min_mip_lookup = minMipLookup_noFilter;
946 947 948
    }
    else
    {
949
        if ((desc->width != pow2_width) || (desc->height != pow2_height))
950
        {
951 952
            texture->pow2_matrix[0] = (((float)desc->width) / ((float)pow2_width));
            texture->pow2_matrix[5] = (((float)desc->height) / ((float)pow2_height));
953
            texture->flags &= ~WINED3D_TEXTURE_POW2_MAT_IDENT;
954 955 956
        }
        else
        {
957 958
            texture->pow2_matrix[0] = 1.0f;
            texture->pow2_matrix[5] = 1.0f;
959 960
        }

961 962 963
        texture->pow2_matrix[10] = 1.0f;
        texture->pow2_matrix[15] = 1.0f;
        texture->target = GL_TEXTURE_2D;
964
    }
965
    TRACE("xf(%f) yf(%f)\n", texture->pow2_matrix[0], texture->pow2_matrix[5]);
966 967

    /* Generate all the surfaces. */
968 969
    surface_desc = *desc;
    surface_desc.resource_type = WINED3D_RTYPE_SURFACE;
970
    for (i = 0; i < texture->level_count; ++i)
971
    {
972
        struct wined3d_surface *surface;
973

974
        if (FAILED(hr = wined3d_surface_create(texture, &surface_desc, surface_flags, &surface)))
975
        {
976
            WARN("Failed to create surface, hr %#x.\n", hr);
977
            wined3d_texture_cleanup(texture);
978 979 980
            return hr;
        }

981
        surface_set_texture_target(surface, texture->target, i);
982
        texture->sub_resources[i] = &surface->resource;
983
        TRACE("Created surface level %u @ %p.\n", i, surface);
984
        /* Calculate the next mipmap level. */
985 986
        surface_desc.width = max(1, surface_desc.width >> 1);
        surface_desc.height = max(1, surface_desc.height >> 1);
987 988 989 990
    }

    return WINED3D_OK;
}
991

992 993
static void texture3d_sub_resource_load(struct wined3d_resource *sub_resource,
        struct wined3d_context *context, BOOL srgb)
994
{
995
    wined3d_volume_load(volume_from_resource(sub_resource), context, srgb);
996 997 998
}

static void texture3d_sub_resource_add_dirty_region(struct wined3d_resource *sub_resource,
999
        const struct wined3d_box *dirty_region)
1000
{
1001
    wined3d_texture_set_dirty(volume_from_resource(sub_resource)->container);
1002 1003 1004 1005
}

static void texture3d_sub_resource_cleanup(struct wined3d_resource *sub_resource)
{
1006
    struct wined3d_volume *volume = volume_from_resource(sub_resource);
1007 1008 1009

    /* Cleanup the container. */
    volume_set_container(volume, NULL);
1010
    wined3d_volume_decref(volume);
1011 1012 1013 1014
}

static const struct wined3d_texture_ops texture3d_ops =
{
1015
    texture3d_sub_resource_load,
1016 1017 1018 1019
    texture3d_sub_resource_add_dirty_region,
    texture3d_sub_resource_cleanup,
};

1020 1021
static HRESULT volumetexture_init(struct wined3d_texture *texture, const struct wined3d_resource_desc *desc,
        UINT levels, struct wined3d_device *device, void *parent, const struct wined3d_parent_ops *parent_ops)
1022 1023
{
    const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1024
    struct wined3d_resource_desc volume_desc;
1025 1026 1027 1028 1029
    unsigned int i;
    HRESULT hr;

    /* TODO: It should only be possible to create textures for formats
     * that are reported as supported. */
1030
    if (WINED3DFMT_UNKNOWN >= desc->format)
1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042
    {
        WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN.\n", texture);
        return WINED3DERR_INVALIDCALL;
    }

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

    /* Calculate levels for mip mapping. */
1043
    if (desc->usage & WINED3DUSAGE_AUTOGENMIPMAP)
1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060
    {
        if (!gl_info->supported[SGIS_GENERATE_MIPMAP])
        {
            WARN("No mipmap generation support, returning D3DERR_INVALIDCALL.\n");
            return WINED3DERR_INVALIDCALL;
        }

        if (levels > 1)
        {
            WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL.\n");
            return WINED3DERR_INVALIDCALL;
        }

        levels = 1;
    }
    else if (!levels)
    {
1061
        levels = wined3d_log2i(max(max(desc->width, desc->height), desc->depth)) + 1;
1062 1063 1064
        TRACE("Calculated levels = %u.\n", levels);
    }

1065 1066 1067 1068
    if (!gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO])
    {
        UINT pow2_w, pow2_h, pow2_d;
        pow2_w = 1;
1069 1070
        while (pow2_w < desc->width)
            pow2_w <<= 1;
1071
        pow2_h = 1;
1072 1073
        while (pow2_h < desc->height)
            pow2_h <<= 1;
1074
        pow2_d = 1;
1075 1076
        while (pow2_d < desc->depth)
            pow2_d <<= 1;
1077

1078
        if (pow2_w != desc->width || pow2_h != desc->height || pow2_d != desc->depth)
1079
        {
1080
            if (desc->pool == WINED3D_POOL_SCRATCH)
1081 1082 1083 1084 1085
            {
                WARN("Creating a scratch NPOT volume texture despite lack of HW support.\n");
            }
            else
            {
1086 1087
                WARN("Attempted to create a NPOT volume texture (%u, %u, %u) without GL support.\n",
                        desc->width, desc->height, desc->depth);
1088 1089 1090 1091 1092
                return WINED3DERR_INVALIDCALL;
            }
        }
    }

1093
    if (FAILED(hr = wined3d_texture_init(texture, &texture3d_ops, 1, levels,
1094
            desc, device, parent, parent_ops, &texture_resource_ops)))
1095
    {
1096
        WARN("Failed to initialize texture, returning %#x.\n", hr);
1097 1098 1099
        return hr;
    }

1100 1101 1102 1103 1104
    texture->pow2_matrix[0] = 1.0f;
    texture->pow2_matrix[5] = 1.0f;
    texture->pow2_matrix[10] = 1.0f;
    texture->pow2_matrix[15] = 1.0f;
    texture->target = GL_TEXTURE_3D;
1105 1106

    /* Generate all the surfaces. */
1107 1108
    volume_desc = *desc;
    volume_desc.resource_type = WINED3D_RTYPE_VOLUME;
1109
    for (i = 0; i < texture->level_count; ++i)
1110
    {
1111
        struct wined3d_volume *volume;
1112

1113
        if (FAILED(hr = wined3d_volume_create(texture, &volume_desc, i, &volume)))
1114 1115
        {
            ERR("Creating a volume for the volume texture failed, hr %#x.\n", hr);
1116
            wined3d_texture_cleanup(texture);
1117 1118 1119
            return hr;
        }

1120
        texture->sub_resources[i] = &volume->resource;
1121 1122

        /* Calculate the next mipmap level. */
1123 1124 1125
        volume_desc.width = max(1, volume_desc.width >> 1);
        volume_desc.height = max(1, volume_desc.height >> 1);
        volume_desc.depth = max(1, volume_desc.depth >> 1);
1126 1127 1128 1129
    }

    return WINED3D_OK;
}
1130

1131
HRESULT CDECL wined3d_texture_create(struct wined3d_device *device, const struct wined3d_resource_desc *desc,
1132 1133
        UINT level_count, DWORD surface_flags, void *parent, const struct wined3d_parent_ops *parent_ops,
        struct wined3d_texture **texture)
1134 1135 1136 1137
{
    struct wined3d_texture *object;
    HRESULT hr;

1138 1139
    TRACE("device %p, desc %p, level_count %u, surface_flags %#x, parent %p, parent_ops %p, texture %p.\n",
            device, desc, level_count, surface_flags, parent, parent_ops, texture);
1140

1141 1142
    if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
        return E_OUTOFMEMORY;
1143

1144
    switch (desc->resource_type)
1145
    {
1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161
        case WINED3D_RTYPE_TEXTURE:
            hr = texture_init(object, desc, level_count, surface_flags, device, parent, parent_ops);
            break;

        case WINED3D_RTYPE_VOLUME_TEXTURE:
            hr = volumetexture_init(object, desc, level_count, device, parent, parent_ops);
            break;

        case WINED3D_RTYPE_CUBE_TEXTURE:
            hr = cubetexture_init(object, desc, level_count, surface_flags, device, parent, parent_ops);
            break;

        default:
            ERR("Invalid resource type %s.\n", debug_d3dresourcetype(desc->resource_type));
            hr = WINED3DERR_INVALIDCALL;
            break;
1162 1163
    }

1164
    if (FAILED(hr))
1165
    {
1166
        WARN("Failed to initialize texture, returning %#x.\n", hr);
1167 1168 1169 1170 1171 1172 1173 1174 1175
        HeapFree(GetProcessHeap(), 0, object);
        return hr;
    }

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

    return WINED3D_OK;
}