ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

texture.c
Go to the documentation of this file.
00001 /*
00002  * Copyright 2002-2005 Jason Edmeades
00003  * Copyright 2002-2005 Raphael Junqueira
00004  * Copyright 2005 Oliver Stieber
00005  * Copyright 2007-2008 Stefan Dösinger for CodeWeavers
00006  * Copyright 2009-2011 Henri Verbeet for CodeWeavers
00007  *
00008  * This library is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Lesser General Public
00010  * License as published by the Free Software Foundation; either
00011  * version 2.1 of the License, or (at your option) any later version.
00012  *
00013  * This library is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  * Lesser General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with this library; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00021  */
00022 
00023 #include "config.h"
00024 #include "wined3d_private.h"
00025 
00026 WINE_DEFAULT_DEBUG_CHANNEL(d3d_texture);
00027 
00028 static HRESULT wined3d_texture_init(struct wined3d_texture *texture, const struct wined3d_texture_ops *texture_ops,
00029         UINT layer_count, UINT level_count, enum wined3d_resource_type resource_type, struct wined3d_device *device,
00030         DWORD usage, const struct wined3d_format *format, enum wined3d_pool pool, void *parent,
00031         const struct wined3d_parent_ops *parent_ops, const struct wined3d_resource_ops *resource_ops)
00032 {
00033     HRESULT hr;
00034 
00035     hr = resource_init(&texture->resource, device, resource_type, format,
00036             WINED3D_MULTISAMPLE_NONE, 0, usage, pool, 0, 0, 0, 0,
00037             parent, parent_ops, resource_ops);
00038     if (FAILED(hr))
00039     {
00040         WARN("Failed to initialize resource, returning %#x\n", hr);
00041         return hr;
00042     }
00043 
00044     texture->texture_ops = texture_ops;
00045     texture->sub_resources = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
00046             level_count * layer_count * sizeof(*texture->sub_resources));
00047     if (!texture->sub_resources)
00048     {
00049         ERR("Failed to allocate sub-resource array.\n");
00050         resource_cleanup(&texture->resource);
00051         return E_OUTOFMEMORY;
00052     }
00053 
00054     texture->layer_count = layer_count;
00055     texture->level_count = level_count;
00056     texture->filter_type = (usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3D_TEXF_LINEAR : WINED3D_TEXF_NONE;
00057     texture->lod = 0;
00058     texture->texture_rgb.dirty = TRUE;
00059     texture->texture_srgb.dirty = TRUE;
00060     texture->flags = WINED3D_TEXTURE_POW2_MAT_IDENT;
00061 
00062     if (texture->resource.format->flags & WINED3DFMT_FLAG_FILTERING)
00063     {
00064         texture->min_mip_lookup = minMipLookup;
00065         texture->mag_lookup = magLookup;
00066     }
00067     else
00068     {
00069         texture->min_mip_lookup = minMipLookup_noFilter;
00070         texture->mag_lookup = magLookup_noFilter;
00071     }
00072 
00073     return WINED3D_OK;
00074 }
00075 
00076 /* A GL context is provided by the caller */
00077 static void gltexture_delete(struct gl_texture *tex)
00078 {
00079     ENTER_GL();
00080     glDeleteTextures(1, &tex->name);
00081     LEAVE_GL();
00082     tex->name = 0;
00083 }
00084 
00085 static void wined3d_texture_unload(struct wined3d_texture *texture)
00086 {
00087     struct wined3d_device *device = texture->resource.device;
00088     struct wined3d_context *context = NULL;
00089 
00090     if (texture->texture_rgb.name || texture->texture_srgb.name)
00091     {
00092         context = context_acquire(device, NULL);
00093     }
00094 
00095     if (texture->texture_rgb.name)
00096         gltexture_delete(&texture->texture_rgb);
00097 
00098     if (texture->texture_srgb.name)
00099         gltexture_delete(&texture->texture_srgb);
00100 
00101     if (context) context_release(context);
00102 
00103     wined3d_texture_set_dirty(texture, TRUE);
00104 
00105     resource_unload(&texture->resource);
00106 }
00107 
00108 static void wined3d_texture_cleanup(struct wined3d_texture *texture)
00109 {
00110     UINT sub_count = texture->level_count * texture->layer_count;
00111     UINT i;
00112 
00113     TRACE("texture %p.\n", texture);
00114 
00115     for (i = 0; i < sub_count; ++i)
00116     {
00117         struct wined3d_resource *sub_resource = texture->sub_resources[i];
00118 
00119         if (sub_resource)
00120             texture->texture_ops->texture_sub_resource_cleanup(sub_resource);
00121     }
00122 
00123     wined3d_texture_unload(texture);
00124     HeapFree(GetProcessHeap(), 0, texture->sub_resources);
00125     resource_cleanup(&texture->resource);
00126 }
00127 
00128 void wined3d_texture_set_dirty(struct wined3d_texture *texture, BOOL dirty)
00129 {
00130     texture->texture_rgb.dirty = dirty;
00131     texture->texture_srgb.dirty = dirty;
00132 }
00133 
00134 /* Context activation is done by the caller. */
00135 static HRESULT wined3d_texture_bind(struct wined3d_texture *texture,
00136         struct wined3d_context *context, BOOL srgb, BOOL *set_surface_desc)
00137 {
00138     struct gl_texture *gl_tex;
00139     BOOL new_texture = FALSE;
00140     HRESULT hr = WINED3D_OK;
00141     GLenum target;
00142 
00143     TRACE("texture %p, context %p, srgb %#x, set_surface_desc %p.\n", texture, context, srgb, set_surface_desc);
00144 
00145     /* sRGB mode cache for preload() calls outside drawprim. */
00146     if (srgb)
00147         texture->flags |= WINED3D_TEXTURE_IS_SRGB;
00148     else
00149         texture->flags &= ~WINED3D_TEXTURE_IS_SRGB;
00150 
00151     gl_tex = wined3d_texture_get_gl_texture(texture, context->gl_info, srgb);
00152     target = texture->target;
00153 
00154     ENTER_GL();
00155     /* Generate a texture name if we don't already have one. */
00156     if (!gl_tex->name)
00157     {
00158         *set_surface_desc = TRUE;
00159         glGenTextures(1, &gl_tex->name);
00160         checkGLcall("glGenTextures");
00161         TRACE("Generated texture %d.\n", gl_tex->name);
00162         if (texture->resource.pool == WINED3D_POOL_DEFAULT)
00163         {
00164             /* Tell OpenGL to try and keep this texture in video ram (well mostly). */
00165             GLclampf tmp = 0.9f;
00166             glPrioritizeTextures(1, &gl_tex->name, &tmp);
00167         }
00168         /* Initialise the state of the texture object to the OpenGL defaults,
00169          * not the D3D defaults. */
00170         gl_tex->states[WINED3DTEXSTA_ADDRESSU] = WINED3D_TADDRESS_WRAP;
00171         gl_tex->states[WINED3DTEXSTA_ADDRESSV] = WINED3D_TADDRESS_WRAP;
00172         gl_tex->states[WINED3DTEXSTA_ADDRESSW] = WINED3D_TADDRESS_WRAP;
00173         gl_tex->states[WINED3DTEXSTA_BORDERCOLOR] = 0;
00174         gl_tex->states[WINED3DTEXSTA_MAGFILTER] = WINED3D_TEXF_LINEAR;
00175         gl_tex->states[WINED3DTEXSTA_MINFILTER] = WINED3D_TEXF_POINT; /* GL_NEAREST_MIPMAP_LINEAR */
00176         gl_tex->states[WINED3DTEXSTA_MIPFILTER] = WINED3D_TEXF_LINEAR; /* GL_NEAREST_MIPMAP_LINEAR */
00177         gl_tex->states[WINED3DTEXSTA_MAXMIPLEVEL] = 0;
00178         gl_tex->states[WINED3DTEXSTA_MAXANISOTROPY] = 1;
00179         if (context->gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
00180             gl_tex->states[WINED3DTEXSTA_SRGBTEXTURE] = TRUE;
00181         else
00182             gl_tex->states[WINED3DTEXSTA_SRGBTEXTURE] = srgb;
00183         gl_tex->states[WINED3DTEXSTA_SHADOW] = FALSE;
00184         wined3d_texture_set_dirty(texture, TRUE);
00185         new_texture = TRUE;
00186 
00187         if (texture->resource.usage & WINED3DUSAGE_AUTOGENMIPMAP)
00188         {
00189             /* This means double binding the texture at creation, but keeps
00190              * the code simpler all in all, and the run-time path free from
00191              * additional checks. */
00192             context_bind_texture(context, target, gl_tex->name);
00193             glTexParameteri(target, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
00194             checkGLcall("glTexParameteri(target, GL_GENERATE_MIPMAP_SGIS, GL_TRUE)");
00195         }
00196     }
00197     else
00198     {
00199         *set_surface_desc = FALSE;
00200     }
00201 
00202     if (gl_tex->name)
00203     {
00204         context_bind_texture(context, target, gl_tex->name);
00205         if (new_texture)
00206         {
00207             /* For a new texture we have to set the texture levels after
00208              * binding the texture. Beware that texture rectangles do not
00209              * support mipmapping, but set the maxmiplevel if we're relying
00210              * on the partial GL_ARB_texture_non_power_of_two emulation with
00211              * texture rectangles. (I.e., do not care about cond_np2 here,
00212              * just look for GL_TEXTURE_RECTANGLE_ARB.) */
00213             if (target != GL_TEXTURE_RECTANGLE_ARB)
00214             {
00215                 TRACE("Setting GL_TEXTURE_MAX_LEVEL to %u.\n", texture->level_count - 1);
00216                 glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, texture->level_count - 1);
00217                 checkGLcall("glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, texture->level_count)");
00218             }
00219             if (target == GL_TEXTURE_CUBE_MAP_ARB)
00220             {
00221                 /* Cubemaps are always set to clamp, regardless of the sampler state. */
00222                 glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
00223                 glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
00224                 glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
00225             }
00226         }
00227     }
00228     else
00229     {
00230         ERR("This texture doesn't have an OpenGL texture assigned to it.\n");
00231         hr = WINED3DERR_INVALIDCALL;
00232     }
00233 
00234     LEAVE_GL();
00235     return hr;
00236 }
00237 
00238 /* GL locking is done by the caller */
00239 static void apply_wrap(const struct wined3d_gl_info *gl_info, GLenum target,
00240         enum wined3d_texture_address d3d_wrap, GLenum param, BOOL cond_np2)
00241 {
00242     GLint gl_wrap;
00243 
00244     if (d3d_wrap < WINED3D_TADDRESS_WRAP || d3d_wrap > WINED3D_TADDRESS_MIRROR_ONCE)
00245     {
00246         FIXME("Unrecognized or unsupported texture address mode %#x.\n", d3d_wrap);
00247         return;
00248     }
00249 
00250     /* Cubemaps are always set to clamp, regardless of the sampler state. */
00251     if (target == GL_TEXTURE_CUBE_MAP_ARB
00252             || (cond_np2 && d3d_wrap == WINED3D_TADDRESS_WRAP))
00253         gl_wrap = GL_CLAMP_TO_EDGE;
00254     else
00255         gl_wrap = gl_info->wrap_lookup[d3d_wrap - WINED3D_TADDRESS_WRAP];
00256 
00257     TRACE("Setting param %#x to %#x for target %#x.\n", param, gl_wrap, target);
00258     glTexParameteri(target, param, gl_wrap);
00259     checkGLcall("glTexParameteri(target, param, gl_wrap)");
00260 }
00261 
00262 /* GL locking is done by the caller (state handler) */
00263 void wined3d_texture_apply_state_changes(struct wined3d_texture *texture,
00264         const DWORD sampler_states[WINED3D_HIGHEST_SAMPLER_STATE + 1],
00265         const struct wined3d_gl_info *gl_info)
00266 {
00267     BOOL cond_np2 = texture->flags & WINED3D_TEXTURE_COND_NP2;
00268     GLenum target = texture->target;
00269     struct gl_texture *gl_tex;
00270     DWORD state;
00271     DWORD aniso;
00272 
00273     TRACE("texture %p, sampler_states %p.\n", texture, sampler_states);
00274 
00275     gl_tex = wined3d_texture_get_gl_texture(texture, gl_info,
00276             texture->flags & WINED3D_TEXTURE_IS_SRGB);
00277 
00278     /* This function relies on the correct texture being bound and loaded. */
00279 
00280     if (sampler_states[WINED3D_SAMP_ADDRESS_U] != gl_tex->states[WINED3DTEXSTA_ADDRESSU])
00281     {
00282         state = sampler_states[WINED3D_SAMP_ADDRESS_U];
00283         apply_wrap(gl_info, target, state, GL_TEXTURE_WRAP_S, cond_np2);
00284         gl_tex->states[WINED3DTEXSTA_ADDRESSU] = state;
00285     }
00286 
00287     if (sampler_states[WINED3D_SAMP_ADDRESS_V] != gl_tex->states[WINED3DTEXSTA_ADDRESSV])
00288     {
00289         state = sampler_states[WINED3D_SAMP_ADDRESS_V];
00290         apply_wrap(gl_info, target, state, GL_TEXTURE_WRAP_T, cond_np2);
00291         gl_tex->states[WINED3DTEXSTA_ADDRESSV] = state;
00292     }
00293 
00294     if (sampler_states[WINED3D_SAMP_ADDRESS_W] != gl_tex->states[WINED3DTEXSTA_ADDRESSW])
00295     {
00296         state = sampler_states[WINED3D_SAMP_ADDRESS_W];
00297         apply_wrap(gl_info, target, state, GL_TEXTURE_WRAP_R, cond_np2);
00298         gl_tex->states[WINED3DTEXSTA_ADDRESSW] = state;
00299     }
00300 
00301     if (sampler_states[WINED3D_SAMP_BORDER_COLOR] != gl_tex->states[WINED3DTEXSTA_BORDERCOLOR])
00302     {
00303         float col[4];
00304 
00305         state = sampler_states[WINED3D_SAMP_BORDER_COLOR];
00306         D3DCOLORTOGLFLOAT4(state, col);
00307         TRACE("Setting border color for %#x to %#x.\n", target, state);
00308         glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, &col[0]);
00309         checkGLcall("glTexParameterfv(..., GL_TEXTURE_BORDER_COLOR, ...)");
00310         gl_tex->states[WINED3DTEXSTA_BORDERCOLOR] = state;
00311     }
00312 
00313     if (sampler_states[WINED3D_SAMP_MAG_FILTER] != gl_tex->states[WINED3DTEXSTA_MAGFILTER])
00314     {
00315         GLint gl_value;
00316 
00317         state = sampler_states[WINED3D_SAMP_MAG_FILTER];
00318         if (state > WINED3D_TEXF_ANISOTROPIC)
00319             FIXME("Unrecognized or unsupported MAGFILTER* value %d.\n", state);
00320 
00321         gl_value = wined3d_gl_mag_filter(texture->mag_lookup,
00322                 min(max(state, WINED3D_TEXF_POINT), WINED3D_TEXF_LINEAR));
00323         TRACE("ValueMAG=%#x setting MAGFILTER to %#x.\n", state, gl_value);
00324         glTexParameteri(target, GL_TEXTURE_MAG_FILTER, gl_value);
00325 
00326         gl_tex->states[WINED3DTEXSTA_MAGFILTER] = state;
00327     }
00328 
00329     if ((sampler_states[WINED3D_SAMP_MIN_FILTER] != gl_tex->states[WINED3DTEXSTA_MINFILTER]
00330             || sampler_states[WINED3D_SAMP_MIP_FILTER] != gl_tex->states[WINED3DTEXSTA_MIPFILTER]
00331             || sampler_states[WINED3D_SAMP_MAX_MIP_LEVEL] != gl_tex->states[WINED3DTEXSTA_MAXMIPLEVEL]))
00332     {
00333         GLint gl_value;
00334 
00335         gl_tex->states[WINED3DTEXSTA_MIPFILTER] = sampler_states[WINED3D_SAMP_MIP_FILTER];
00336         gl_tex->states[WINED3DTEXSTA_MINFILTER] = sampler_states[WINED3D_SAMP_MIN_FILTER];
00337         gl_tex->states[WINED3DTEXSTA_MAXMIPLEVEL] = sampler_states[WINED3D_SAMP_MAX_MIP_LEVEL];
00338 
00339         if (gl_tex->states[WINED3DTEXSTA_MINFILTER] > WINED3D_TEXF_ANISOTROPIC
00340             || gl_tex->states[WINED3DTEXSTA_MIPFILTER] > WINED3D_TEXF_ANISOTROPIC)
00341         {
00342             FIXME("Unrecognized or unsupported MIN_FILTER value %#x MIP_FILTER value %#x.\n",
00343                   gl_tex->states[WINED3DTEXSTA_MINFILTER],
00344                   gl_tex->states[WINED3DTEXSTA_MIPFILTER]);
00345         }
00346         gl_value = wined3d_gl_min_mip_filter(texture->min_mip_lookup,
00347                 min(max(sampler_states[WINED3D_SAMP_MIN_FILTER], WINED3D_TEXF_POINT), WINED3D_TEXF_LINEAR),
00348                 min(max(sampler_states[WINED3D_SAMP_MIP_FILTER], WINED3D_TEXF_NONE), WINED3D_TEXF_LINEAR));
00349 
00350         TRACE("ValueMIN=%#x, ValueMIP=%#x, setting MINFILTER to %#x.\n",
00351               sampler_states[WINED3D_SAMP_MIN_FILTER],
00352               sampler_states[WINED3D_SAMP_MIP_FILTER], gl_value);
00353         glTexParameteri(target, GL_TEXTURE_MIN_FILTER, gl_value);
00354         checkGLcall("glTexParameter GL_TEXTURE_MIN_FILTER, ...");
00355 
00356         if (!cond_np2)
00357         {
00358             if (gl_tex->states[WINED3DTEXSTA_MIPFILTER] == WINED3D_TEXF_NONE)
00359                 gl_value = texture->lod;
00360             else if (gl_tex->states[WINED3DTEXSTA_MAXMIPLEVEL] >= texture->level_count)
00361                 gl_value = texture->level_count - 1;
00362             else if (gl_tex->states[WINED3DTEXSTA_MAXMIPLEVEL] < texture->lod)
00363                 /* texture->lod is already clamped in the setter. */
00364                 gl_value = texture->lod;
00365             else
00366                 gl_value = gl_tex->states[WINED3DTEXSTA_MAXMIPLEVEL];
00367 
00368             /* Note that WINED3D_SAMP_MAX_MIP_LEVEL specifies the largest mipmap
00369              * (default 0), while GL_TEXTURE_MAX_LEVEL specifies the smallest
00370              * mimap used (default 1000). So WINED3D_SAMP_MAX_MIP_LEVEL
00371              * corresponds to GL_TEXTURE_BASE_LEVEL. */
00372             glTexParameteri(target, GL_TEXTURE_BASE_LEVEL, gl_value);
00373         }
00374     }
00375 
00376     if ((gl_tex->states[WINED3DTEXSTA_MAGFILTER] != WINED3D_TEXF_ANISOTROPIC
00377             && gl_tex->states[WINED3DTEXSTA_MINFILTER] != WINED3D_TEXF_ANISOTROPIC
00378             && gl_tex->states[WINED3DTEXSTA_MIPFILTER] != WINED3D_TEXF_ANISOTROPIC)
00379             || cond_np2)
00380         aniso = 1;
00381     else
00382         aniso = sampler_states[WINED3D_SAMP_MAX_ANISOTROPY];
00383 
00384     if (gl_tex->states[WINED3DTEXSTA_MAXANISOTROPY] != aniso)
00385     {
00386         if (gl_info->supported[EXT_TEXTURE_FILTER_ANISOTROPIC])
00387         {
00388             glTexParameteri(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);
00389             checkGLcall("glTexParameteri(GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso)");
00390         }
00391         else
00392         {
00393             WARN("Anisotropic filtering not supported.\n");
00394         }
00395         gl_tex->states[WINED3DTEXSTA_MAXANISOTROPY] = aniso;
00396     }
00397 
00398     /* These should always be the same unless EXT_texture_sRGB_decode is supported. */
00399     if (sampler_states[WINED3D_SAMP_SRGB_TEXTURE] != gl_tex->states[WINED3DTEXSTA_SRGBTEXTURE])
00400     {
00401         glTexParameteri(target, GL_TEXTURE_SRGB_DECODE_EXT,
00402                 sampler_states[WINED3D_SAMP_SRGB_TEXTURE] ? GL_DECODE_EXT : GL_SKIP_DECODE_EXT);
00403         checkGLcall("glTexParameteri(GL_TEXTURE_SRGB_DECODE_EXT)");
00404         gl_tex->states[WINED3DTEXSTA_SRGBTEXTURE] = sampler_states[WINED3D_SAMP_SRGB_TEXTURE];
00405     }
00406 
00407     if (!(texture->resource.format->flags & WINED3DFMT_FLAG_SHADOW)
00408             != !gl_tex->states[WINED3DTEXSTA_SHADOW])
00409     {
00410         if (texture->resource.format->flags & WINED3DFMT_FLAG_SHADOW)
00411         {
00412             glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
00413             glTexParameteri(target, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
00414             checkGLcall("glTexParameteri(target, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB)");
00415             gl_tex->states[WINED3DTEXSTA_SHADOW] = TRUE;
00416         }
00417         else
00418         {
00419             glTexParameteri(target, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
00420             checkGLcall("glTexParameteri(target, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE)");
00421             gl_tex->states[WINED3DTEXSTA_SHADOW] = FALSE;
00422         }
00423     }
00424 }
00425 
00426 ULONG CDECL wined3d_texture_incref(struct wined3d_texture *texture)
00427 {
00428     ULONG refcount = InterlockedIncrement(&texture->resource.ref);
00429 
00430     TRACE("%p increasing refcount to %u.\n", texture, refcount);
00431 
00432     return refcount;
00433 }
00434 
00435 /* Do not call while under the GL lock. */
00436 ULONG CDECL wined3d_texture_decref(struct wined3d_texture *texture)
00437 {
00438     ULONG refcount = InterlockedDecrement(&texture->resource.ref);
00439 
00440     TRACE("%p decreasing refcount to %u.\n", texture, refcount);
00441 
00442     if (!refcount)
00443     {
00444         wined3d_texture_cleanup(texture);
00445         texture->resource.parent_ops->wined3d_object_destroyed(texture->resource.parent);
00446         HeapFree(GetProcessHeap(), 0, texture);
00447     }
00448 
00449     return refcount;
00450 }
00451 
00452 struct wined3d_resource * CDECL wined3d_texture_get_resource(struct wined3d_texture *texture)
00453 {
00454     TRACE("texture %p.\n", texture);
00455 
00456     return &texture->resource;
00457 }
00458 
00459 DWORD CDECL wined3d_texture_set_priority(struct wined3d_texture *texture, DWORD priority)
00460 {
00461     return resource_set_priority(&texture->resource, priority);
00462 }
00463 
00464 DWORD CDECL wined3d_texture_get_priority(const struct wined3d_texture *texture)
00465 {
00466     return resource_get_priority(&texture->resource);
00467 }
00468 
00469 /* Do not call while under the GL lock. */
00470 void CDECL wined3d_texture_preload(struct wined3d_texture *texture)
00471 {
00472     texture->texture_ops->texture_preload(texture, SRGB_ANY);
00473 }
00474 
00475 void * CDECL wined3d_texture_get_parent(const struct wined3d_texture *texture)
00476 {
00477     TRACE("texture %p.\n", texture);
00478 
00479     return texture->resource.parent;
00480 }
00481 
00482 DWORD CDECL wined3d_texture_set_lod(struct wined3d_texture *texture, DWORD lod)
00483 {
00484     DWORD old = texture->lod;
00485 
00486     TRACE("texture %p, lod %u.\n", texture, lod);
00487 
00488     /* The d3d9:texture test shows that SetLOD is ignored on non-managed
00489      * textures. The call always returns 0, and GetLOD always returns 0. */
00490     if (texture->resource.pool != WINED3D_POOL_MANAGED)
00491     {
00492         TRACE("Ignoring SetLOD on %s texture, returning 0.\n", debug_d3dpool(texture->resource.pool));
00493         return 0;
00494     }
00495 
00496     if (lod >= texture->level_count)
00497         lod = texture->level_count - 1;
00498 
00499     if (texture->lod != lod)
00500     {
00501         texture->lod = lod;
00502 
00503         texture->texture_rgb.states[WINED3DTEXSTA_MAXMIPLEVEL] = ~0U;
00504         texture->texture_srgb.states[WINED3DTEXSTA_MAXMIPLEVEL] = ~0U;
00505         if (texture->bind_count)
00506             device_invalidate_state(texture->resource.device, STATE_SAMPLER(texture->sampler));
00507     }
00508 
00509     return old;
00510 }
00511 
00512 DWORD CDECL wined3d_texture_get_lod(const struct wined3d_texture *texture)
00513 {
00514     TRACE("texture %p, returning %u.\n", texture, texture->lod);
00515 
00516     return texture->lod;
00517 }
00518 
00519 DWORD CDECL wined3d_texture_get_level_count(const struct wined3d_texture *texture)
00520 {
00521     TRACE("texture %p, returning %u.\n", texture, texture->level_count);
00522 
00523     return texture->level_count;
00524 }
00525 
00526 HRESULT CDECL wined3d_texture_set_autogen_filter_type(struct wined3d_texture *texture,
00527         enum wined3d_texture_filter_type filter_type)
00528 {
00529     FIXME("texture %p, filter_type %s stub!\n", texture, debug_d3dtexturefiltertype(filter_type));
00530 
00531     if (!(texture->resource.usage & WINED3DUSAGE_AUTOGENMIPMAP))
00532     {
00533         WARN("Texture doesn't have AUTOGENMIPMAP usage.\n");
00534         return WINED3DERR_INVALIDCALL;
00535     }
00536 
00537     texture->filter_type = filter_type;
00538 
00539     return WINED3D_OK;
00540 }
00541 
00542 enum wined3d_texture_filter_type CDECL wined3d_texture_get_autogen_filter_type(const struct wined3d_texture *texture)
00543 {
00544     TRACE("texture %p.\n", texture);
00545 
00546     return texture->filter_type;
00547 }
00548 
00549 void CDECL wined3d_texture_generate_mipmaps(struct wined3d_texture *texture)
00550 {
00551     /* TODO: Implement filters using GL_SGI_generate_mipmaps. */
00552     FIXME("texture %p stub!\n", texture);
00553 }
00554 
00555 struct wined3d_resource * CDECL wined3d_texture_get_sub_resource(struct wined3d_texture *texture,
00556         UINT sub_resource_idx)
00557 {
00558     UINT sub_count = texture->level_count * texture->layer_count;
00559 
00560     TRACE("texture %p, sub_resource_idx %u.\n", texture, sub_resource_idx);
00561 
00562     if (sub_resource_idx >= sub_count)
00563     {
00564         WARN("sub_resource_idx %u >= sub_count %u.\n", sub_resource_idx, sub_count);
00565         return NULL;
00566     }
00567 
00568     return texture->sub_resources[sub_resource_idx];
00569 }
00570 
00571 HRESULT CDECL wined3d_texture_add_dirty_region(struct wined3d_texture *texture,
00572         UINT layer, const struct wined3d_box *dirty_region)
00573 {
00574     struct wined3d_resource *sub_resource;
00575 
00576     TRACE("texture %p, layer %u, dirty_region %p.\n", texture, layer, dirty_region);
00577 
00578     if (!(sub_resource = wined3d_texture_get_sub_resource(texture, layer * texture->level_count)))
00579     {
00580         WARN("Failed to get sub-resource.\n");
00581         return WINED3DERR_INVALIDCALL;
00582     }
00583 
00584     wined3d_texture_set_dirty(texture, TRUE);
00585     texture->texture_ops->texture_sub_resource_add_dirty_region(sub_resource, dirty_region);
00586 
00587     return WINED3D_OK;
00588 }
00589 
00590 /* Context activation is done by the caller. */
00591 static HRESULT texture2d_bind(struct wined3d_texture *texture,
00592         struct wined3d_context *context, BOOL srgb)
00593 {
00594     BOOL set_gl_texture_desc;
00595     HRESULT hr;
00596 
00597     TRACE("texture %p, context %p, srgb %#x.\n", texture, context, srgb);
00598 
00599     hr = wined3d_texture_bind(texture, context, srgb, &set_gl_texture_desc);
00600     if (set_gl_texture_desc && SUCCEEDED(hr))
00601     {
00602         UINT sub_count = texture->level_count * texture->layer_count;
00603         BOOL srgb_tex = !context->gl_info->supported[EXT_TEXTURE_SRGB_DECODE]
00604                 && (texture->flags & WINED3D_TEXTURE_IS_SRGB);
00605         struct gl_texture *gl_tex;
00606         UINT i;
00607 
00608         gl_tex = wined3d_texture_get_gl_texture(texture, context->gl_info, srgb_tex);
00609 
00610         for (i = 0; i < sub_count; ++i)
00611         {
00612             struct wined3d_surface *surface = surface_from_resource(texture->sub_resources[i]);
00613             surface_set_texture_name(surface, gl_tex->name, srgb_tex);
00614         }
00615 
00616         /* Conditinal non power of two textures use a different clamping
00617          * default. If we're using the GL_WINE_normalized_texrect partial
00618          * driver emulation, we're dealing with a GL_TEXTURE_2D texture which
00619          * has the address mode set to repeat - something that prevents us
00620          * from hitting the accelerated codepath. Thus manually set the GL
00621          * state. The same applies to filtering. Even if the texture has only
00622          * one mip level, the default LINEAR_MIPMAP_LINEAR filter causes a SW
00623          * fallback on macos. */
00624         if (texture->flags & WINED3D_TEXTURE_COND_NP2)
00625         {
00626             GLenum target = texture->target;
00627 
00628             ENTER_GL();
00629             glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
00630             checkGLcall("glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)");
00631             glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
00632             checkGLcall("glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)");
00633             glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
00634             checkGLcall("glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST)");
00635             glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
00636             checkGLcall("glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST)");
00637             LEAVE_GL();
00638             gl_tex->states[WINED3DTEXSTA_ADDRESSU] = WINED3D_TADDRESS_CLAMP;
00639             gl_tex->states[WINED3DTEXSTA_ADDRESSV] = WINED3D_TADDRESS_CLAMP;
00640             gl_tex->states[WINED3DTEXSTA_MAGFILTER] = WINED3D_TEXF_POINT;
00641             gl_tex->states[WINED3DTEXSTA_MINFILTER] = WINED3D_TEXF_POINT;
00642             gl_tex->states[WINED3DTEXSTA_MIPFILTER] = WINED3D_TEXF_NONE;
00643         }
00644     }
00645 
00646     return hr;
00647 }
00648 
00649 static BOOL texture_srgb_mode(const struct wined3d_texture *texture, enum WINED3DSRGB srgb)
00650 {
00651     switch (srgb)
00652     {
00653         case SRGB_RGB:
00654             return FALSE;
00655 
00656         case SRGB_SRGB:
00657             return TRUE;
00658 
00659         default:
00660             return texture->flags & WINED3D_TEXTURE_IS_SRGB;
00661     }
00662 }
00663 
00664 /* Do not call while under the GL lock. */
00665 static void texture2d_preload(struct wined3d_texture *texture, enum WINED3DSRGB srgb)
00666 {
00667     UINT sub_count = texture->level_count * texture->layer_count;
00668     struct wined3d_device *device = texture->resource.device;
00669     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
00670     struct wined3d_context *context = NULL;
00671     struct gl_texture *gl_tex;
00672     BOOL srgb_mode;
00673     UINT i;
00674 
00675     TRACE("texture %p, srgb %#x.\n", texture, srgb);
00676 
00677     srgb_mode = texture_srgb_mode(texture, srgb);
00678     gl_tex = wined3d_texture_get_gl_texture(texture, gl_info, srgb_mode);
00679 
00680     if (!device->isInDraw)
00681     {
00682         /* No danger of recursive calls, context_acquire() sets isInDraw to TRUE
00683          * when loading offscreen render targets into the texture. */
00684         context = context_acquire(device, NULL);
00685     }
00686 
00687     if (gl_tex->dirty)
00688     {
00689         /* Reload the surfaces if the texture is marked dirty. */
00690         for (i = 0; i < sub_count; ++i)
00691         {
00692             surface_load(surface_from_resource(texture->sub_resources[i]), srgb_mode);
00693         }
00694     }
00695     else
00696     {
00697         TRACE("Texture %p not dirty, nothing to do.\n", texture);
00698     }
00699 
00700     /* No longer dirty. */
00701     gl_tex->dirty = FALSE;
00702 
00703     if (context) context_release(context);
00704 }
00705 
00706 static void texture2d_sub_resource_add_dirty_region(struct wined3d_resource *sub_resource,
00707         const struct wined3d_box *dirty_region)
00708 {
00709     surface_add_dirty_rect(surface_from_resource(sub_resource), dirty_region);
00710 }
00711 
00712 static void texture2d_sub_resource_cleanup(struct wined3d_resource *sub_resource)
00713 {
00714     struct wined3d_surface *surface = surface_from_resource(sub_resource);
00715 
00716     /* Clean out the texture name we gave to the surface so that the
00717      * surface doesn't try and release it. */
00718     surface_set_texture_name(surface, 0, TRUE);
00719     surface_set_texture_name(surface, 0, FALSE);
00720     surface_set_texture_target(surface, 0);
00721     surface_set_container(surface, WINED3D_CONTAINER_NONE, NULL);
00722     wined3d_surface_decref(surface);
00723 }
00724 
00725 /* Do not call while under the GL lock. */
00726 static void texture2d_unload(struct wined3d_resource *resource)
00727 {
00728     struct wined3d_texture *texture = wined3d_texture_from_resource(resource);
00729     UINT sub_count = texture->level_count * texture->layer_count;
00730     UINT i;
00731 
00732     TRACE("texture %p.\n", texture);
00733 
00734     for (i = 0; i < sub_count; ++i)
00735     {
00736         struct wined3d_resource *sub_resource = texture->sub_resources[i];
00737         struct wined3d_surface *surface = surface_from_resource(sub_resource);
00738 
00739         sub_resource->resource_ops->resource_unload(sub_resource);
00740         surface_set_texture_name(surface, 0, FALSE); /* Delete RGB name */
00741         surface_set_texture_name(surface, 0, TRUE); /* Delete sRGB name */
00742     }
00743 
00744     wined3d_texture_unload(texture);
00745 }
00746 
00747 static const struct wined3d_texture_ops texture2d_ops =
00748 {
00749     texture2d_bind,
00750     texture2d_preload,
00751     texture2d_sub_resource_add_dirty_region,
00752     texture2d_sub_resource_cleanup,
00753 };
00754 
00755 static const struct wined3d_resource_ops texture2d_resource_ops =
00756 {
00757     texture2d_unload,
00758 };
00759 
00760 static HRESULT cubetexture_init(struct wined3d_texture *texture, UINT edge_length, UINT levels,
00761         struct wined3d_device *device, DWORD usage, enum wined3d_format_id format_id, enum wined3d_pool pool,
00762         void *parent, const struct wined3d_parent_ops *parent_ops)
00763 {
00764     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
00765     const struct wined3d_format *format = wined3d_get_format(gl_info, format_id);
00766     UINT pow2_edge_length;
00767     unsigned int i, j;
00768     UINT tmp_w;
00769     HRESULT hr;
00770 
00771     /* TODO: It should only be possible to create textures for formats
00772      * that are reported as supported. */
00773     if (WINED3DFMT_UNKNOWN >= format_id)
00774     {
00775         WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN.\n", texture);
00776         return WINED3DERR_INVALIDCALL;
00777     }
00778 
00779     if (!gl_info->supported[ARB_TEXTURE_CUBE_MAP] && pool != WINED3D_POOL_SCRATCH)
00780     {
00781         WARN("(%p) : Tried to create not supported cube texture.\n", texture);
00782         return WINED3DERR_INVALIDCALL;
00783     }
00784 
00785     /* Calculate levels for mip mapping */
00786     if (usage & WINED3DUSAGE_AUTOGENMIPMAP)
00787     {
00788         if (!gl_info->supported[SGIS_GENERATE_MIPMAP])
00789         {
00790             WARN("No mipmap generation support, returning D3DERR_INVALIDCALL.\n");
00791             return WINED3DERR_INVALIDCALL;
00792         }
00793 
00794         if (levels > 1)
00795         {
00796             WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL.\n");
00797             return WINED3DERR_INVALIDCALL;
00798         }
00799 
00800         levels = 1;
00801     }
00802     else if (!levels)
00803     {
00804         levels = wined3d_log2i(edge_length) + 1;
00805         TRACE("Calculated levels = %u.\n", levels);
00806     }
00807 
00808     hr = wined3d_texture_init(texture, &texture2d_ops, 6, levels,
00809             WINED3D_RTYPE_CUBE_TEXTURE, device, usage, format, pool,
00810             parent, parent_ops, &texture2d_resource_ops);
00811     if (FAILED(hr))
00812     {
00813         WARN("Failed to initialize texture, returning %#x\n", hr);
00814         return hr;
00815     }
00816 
00817     /* Find the nearest pow2 match. */
00818     pow2_edge_length = 1;
00819     while (pow2_edge_length < edge_length) pow2_edge_length <<= 1;
00820 
00821     if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || (edge_length == pow2_edge_length))
00822     {
00823         /* Precalculated scaling for 'faked' non power of two texture coords. */
00824         texture->pow2_matrix[0] = 1.0f;
00825         texture->pow2_matrix[5] = 1.0f;
00826         texture->pow2_matrix[10] = 1.0f;
00827         texture->pow2_matrix[15] = 1.0f;
00828     }
00829     else
00830     {
00831         /* Precalculated scaling for 'faked' non power of two texture coords. */
00832         texture->pow2_matrix[0] = ((float)edge_length) / ((float)pow2_edge_length);
00833         texture->pow2_matrix[5] = ((float)edge_length) / ((float)pow2_edge_length);
00834         texture->pow2_matrix[10] = ((float)edge_length) / ((float)pow2_edge_length);
00835         texture->pow2_matrix[15] = 1.0f;
00836         texture->flags &= ~WINED3D_TEXTURE_POW2_MAT_IDENT;
00837     }
00838     texture->target = GL_TEXTURE_CUBE_MAP_ARB;
00839 
00840     /* Generate all the surfaces. */
00841     tmp_w = edge_length;
00842     for (i = 0; i < texture->level_count; ++i)
00843     {
00844         /* Create the 6 faces. */
00845         for (j = 0; j < 6; ++j)
00846         {
00847             static const GLenum cube_targets[6] =
00848             {
00849                 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
00850                 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
00851                 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
00852                 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
00853                 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
00854                 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB,
00855             };
00856             UINT idx = j * texture->level_count + i;
00857             struct wined3d_surface *surface;
00858 
00859             hr = device->device_parent->ops->create_surface(device->device_parent, parent, tmp_w, tmp_w,
00860                     format_id, usage, pool, i /* Level */, j, &surface);
00861             if (FAILED(hr))
00862             {
00863                 FIXME("(%p) Failed to create surface, hr %#x.\n", texture, hr);
00864                 wined3d_texture_cleanup(texture);
00865                 return hr;
00866             }
00867 
00868             surface_set_container(surface, WINED3D_CONTAINER_TEXTURE, texture);
00869             surface_set_texture_target(surface, cube_targets[j]);
00870             texture->sub_resources[idx] = &surface->resource;
00871             TRACE("Created surface level %u @ %p.\n", i, surface);
00872         }
00873         tmp_w = max(1, tmp_w >> 1);
00874     }
00875 
00876     return WINED3D_OK;
00877 }
00878 
00879 static HRESULT texture_init(struct wined3d_texture *texture, UINT width, UINT height, UINT levels,
00880         struct wined3d_device *device, DWORD usage, enum wined3d_format_id format_id, enum wined3d_pool pool,
00881         void *parent, const struct wined3d_parent_ops *parent_ops)
00882 {
00883     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
00884     const struct wined3d_format *format = wined3d_get_format(gl_info, format_id);
00885     UINT pow2_width, pow2_height;
00886     UINT tmp_w, tmp_h;
00887     unsigned int i;
00888     HRESULT hr;
00889 
00890     /* TODO: It should only be possible to create textures for formats
00891      * that are reported as supported. */
00892     if (WINED3DFMT_UNKNOWN >= format_id)
00893     {
00894         WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN.\n", texture);
00895         return WINED3DERR_INVALIDCALL;
00896     }
00897 
00898     /* Non-power2 support. */
00899     if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO])
00900     {
00901         pow2_width = width;
00902         pow2_height = height;
00903     }
00904     else
00905     {
00906         /* Find the nearest pow2 match. */
00907         pow2_width = pow2_height = 1;
00908         while (pow2_width < width) pow2_width <<= 1;
00909         while (pow2_height < height) pow2_height <<= 1;
00910 
00911         if (pow2_width != width || pow2_height != height)
00912         {
00913             if (levels > 1)
00914             {
00915                 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support.\n");
00916                 return WINED3DERR_INVALIDCALL;
00917             }
00918             levels = 1;
00919         }
00920     }
00921 
00922     /* Calculate levels for mip mapping. */
00923     if (usage & WINED3DUSAGE_AUTOGENMIPMAP)
00924     {
00925         if (!gl_info->supported[SGIS_GENERATE_MIPMAP])
00926         {
00927             WARN("No mipmap generation support, returning WINED3DERR_INVALIDCALL.\n");
00928             return WINED3DERR_INVALIDCALL;
00929         }
00930 
00931         if (levels > 1)
00932         {
00933             WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning WINED3DERR_INVALIDCALL.\n");
00934             return WINED3DERR_INVALIDCALL;
00935         }
00936 
00937         levels = 1;
00938     }
00939     else if (!levels)
00940     {
00941         levels = wined3d_log2i(max(width, height)) + 1;
00942         TRACE("Calculated levels = %u.\n", levels);
00943     }
00944 
00945     hr = wined3d_texture_init(texture, &texture2d_ops, 1, levels,
00946             WINED3D_RTYPE_TEXTURE, device, usage, format, pool,
00947             parent, parent_ops, &texture2d_resource_ops);
00948     if (FAILED(hr))
00949     {
00950         WARN("Failed to initialize texture, returning %#x.\n", hr);
00951         return hr;
00952     }
00953 
00954     /* Precalculated scaling for 'faked' non power of two texture coords.
00955      * Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
00956      * is used in combination with texture uploads (RTL_READTEX). The reason is that EXT_PALETTED_TEXTURE
00957      * doesn't work in combination with ARB_TEXTURE_RECTANGLE. */
00958     if (gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT] && (width != pow2_width || height != pow2_height))
00959     {
00960         texture->pow2_matrix[0] = 1.0f;
00961         texture->pow2_matrix[5] = 1.0f;
00962         texture->pow2_matrix[10] = 1.0f;
00963         texture->pow2_matrix[15] = 1.0f;
00964         texture->target = GL_TEXTURE_2D;
00965         texture->flags |= WINED3D_TEXTURE_COND_NP2;
00966         texture->min_mip_lookup = minMipLookup_noFilter;
00967     }
00968     else if (gl_info->supported[ARB_TEXTURE_RECTANGLE] && (width != pow2_width || height != pow2_height)
00969             && !(format->id == WINED3DFMT_P8_UINT && gl_info->supported[EXT_PALETTED_TEXTURE]
00970             && wined3d_settings.rendertargetlock_mode == RTL_READTEX))
00971     {
00972         if (width != 1 || height != 1)
00973             texture->flags &= ~WINED3D_TEXTURE_POW2_MAT_IDENT;
00974 
00975         texture->pow2_matrix[0] = (float)width;
00976         texture->pow2_matrix[5] = (float)height;
00977         texture->pow2_matrix[10] = 1.0f;
00978         texture->pow2_matrix[15] = 1.0f;
00979         texture->target = GL_TEXTURE_RECTANGLE_ARB;
00980         texture->flags |= WINED3D_TEXTURE_COND_NP2;
00981 
00982         if (texture->resource.format->flags & WINED3DFMT_FLAG_FILTERING)
00983             texture->min_mip_lookup = minMipLookup_noMip;
00984         else
00985             texture->min_mip_lookup = minMipLookup_noFilter;
00986     }
00987     else
00988     {
00989         if ((width != pow2_width) || (height != pow2_height))
00990         {
00991             texture->pow2_matrix[0] = (((float)width) / ((float)pow2_width));
00992             texture->pow2_matrix[5] = (((float)height) / ((float)pow2_height));
00993             texture->flags &= ~WINED3D_TEXTURE_POW2_MAT_IDENT;
00994         }
00995         else
00996         {
00997             texture->pow2_matrix[0] = 1.0f;
00998             texture->pow2_matrix[5] = 1.0f;
00999         }
01000 
01001         texture->pow2_matrix[10] = 1.0f;
01002         texture->pow2_matrix[15] = 1.0f;
01003         texture->target = GL_TEXTURE_2D;
01004     }
01005     TRACE("xf(%f) yf(%f)\n", texture->pow2_matrix[0], texture->pow2_matrix[5]);
01006 
01007     /* Generate all the surfaces. */
01008     tmp_w = width;
01009     tmp_h = height;
01010     for (i = 0; i < texture->level_count; ++i)
01011     {
01012         struct wined3d_surface *surface;
01013 
01014         /* Use the callback to create the texture surface. */
01015         hr = device->device_parent->ops->create_surface(device->device_parent, parent, tmp_w, tmp_h,
01016                 format->id, usage, pool, i, 0, &surface);
01017         if (FAILED(hr))
01018         {
01019             FIXME("Failed to create surface %p, hr %#x\n", texture, hr);
01020             wined3d_texture_cleanup(texture);
01021             return hr;
01022         }
01023 
01024         surface_set_container(surface, WINED3D_CONTAINER_TEXTURE, texture);
01025         surface_set_texture_target(surface, texture->target);
01026         texture->sub_resources[i] = &surface->resource;
01027         TRACE("Created surface level %u @ %p.\n", i, surface);
01028         /* Calculate the next mipmap level. */
01029         tmp_w = max(1, tmp_w >> 1);
01030         tmp_h = max(1, tmp_h >> 1);
01031     }
01032 
01033     return WINED3D_OK;
01034 }
01035 
01036 /* Context activation is done by the caller. */
01037 static HRESULT texture3d_bind(struct wined3d_texture *texture,
01038         struct wined3d_context *context, BOOL srgb)
01039 {
01040     BOOL dummy;
01041 
01042     TRACE("texture %p, context %p, srgb %#x.\n", texture, context, srgb);
01043 
01044     return wined3d_texture_bind(texture, context, srgb, &dummy);
01045 }
01046 
01047 /* Do not call while under the GL lock. */
01048 static void texture3d_preload(struct wined3d_texture *texture, enum WINED3DSRGB srgb)
01049 {
01050     struct wined3d_device *device = texture->resource.device;
01051     struct wined3d_context *context;
01052     BOOL srgb_was_toggled = FALSE;
01053     unsigned int i;
01054 
01055     TRACE("texture %p, srgb %#x.\n", texture, srgb);
01056 
01057     /* TODO: Use already acquired context when possible. */
01058     context = context_acquire(device, NULL);
01059     if (texture->bind_count > 0)
01060     {
01061         BOOL texture_srgb = texture->flags & WINED3D_TEXTURE_IS_SRGB;
01062         BOOL sampler_srgb = texture_srgb_mode(texture, srgb);
01063         srgb_was_toggled = !texture_srgb != !sampler_srgb;
01064 
01065         if (srgb_was_toggled)
01066         {
01067             if (sampler_srgb)
01068                 texture->flags |= WINED3D_TEXTURE_IS_SRGB;
01069             else
01070                 texture->flags &= ~WINED3D_TEXTURE_IS_SRGB;
01071         }
01072     }
01073 
01074     /* If the texture is marked dirty or the sRGB sampler setting has changed
01075      * since the last load then reload the volumes. */
01076     if (texture->texture_rgb.dirty)
01077     {
01078         for (i = 0; i < texture->level_count; ++i)
01079         {
01080             volume_load(volume_from_resource(texture->sub_resources[i]), context, i,
01081                     texture->flags & WINED3D_TEXTURE_IS_SRGB);
01082         }
01083     }
01084     else if (srgb_was_toggled)
01085     {
01086         for (i = 0; i < texture->level_count; ++i)
01087         {
01088             struct wined3d_volume *volume = volume_from_resource(texture->sub_resources[i]);
01089             volume_add_dirty_box(volume, NULL);
01090             volume_load(volume, context, i, texture->flags & WINED3D_TEXTURE_IS_SRGB);
01091         }
01092     }
01093     else
01094     {
01095         TRACE("Texture %p not dirty, nothing to do.\n", texture);
01096     }
01097 
01098     context_release(context);
01099 
01100     /* No longer dirty */
01101     texture->texture_rgb.dirty = FALSE;
01102 }
01103 
01104 static void texture3d_sub_resource_add_dirty_region(struct wined3d_resource *sub_resource,
01105         const struct wined3d_box *dirty_region)
01106 {
01107     volume_add_dirty_box(volume_from_resource(sub_resource), dirty_region);
01108 }
01109 
01110 static void texture3d_sub_resource_cleanup(struct wined3d_resource *sub_resource)
01111 {
01112     struct wined3d_volume *volume = volume_from_resource(sub_resource);
01113 
01114     /* Cleanup the container. */
01115     volume_set_container(volume, NULL);
01116     wined3d_volume_decref(volume);
01117 }
01118 
01119 /* Do not call while under the GL lock. */
01120 static void texture3d_unload(struct wined3d_resource *resource)
01121 {
01122     struct wined3d_texture *texture = wined3d_texture_from_resource(resource);
01123     UINT i;
01124 
01125     TRACE("texture %p.\n", texture);
01126 
01127     for (i = 0; i < texture->level_count; ++i)
01128     {
01129         struct wined3d_resource *sub_resource = texture->sub_resources[i];
01130         sub_resource->resource_ops->resource_unload(sub_resource);
01131     }
01132 
01133     wined3d_texture_unload(texture);
01134 }
01135 
01136 static const struct wined3d_texture_ops texture3d_ops =
01137 {
01138     texture3d_bind,
01139     texture3d_preload,
01140     texture3d_sub_resource_add_dirty_region,
01141     texture3d_sub_resource_cleanup,
01142 };
01143 
01144 static const struct wined3d_resource_ops texture3d_resource_ops =
01145 {
01146     texture3d_unload,
01147 };
01148 
01149 static HRESULT volumetexture_init(struct wined3d_texture *texture, UINT width, UINT height,
01150         UINT depth, UINT levels, struct wined3d_device *device, DWORD usage, enum wined3d_format_id format_id,
01151         enum wined3d_pool pool, void *parent, const struct wined3d_parent_ops *parent_ops)
01152 {
01153     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
01154     const struct wined3d_format *format = wined3d_get_format(gl_info, format_id);
01155     UINT tmp_w, tmp_h, tmp_d;
01156     unsigned int i;
01157     HRESULT hr;
01158 
01159     /* TODO: It should only be possible to create textures for formats
01160      * that are reported as supported. */
01161     if (WINED3DFMT_UNKNOWN >= format_id)
01162     {
01163         WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN.\n", texture);
01164         return WINED3DERR_INVALIDCALL;
01165     }
01166 
01167     if (!gl_info->supported[EXT_TEXTURE3D])
01168     {
01169         WARN("(%p) : Texture cannot be created - no volume texture support.\n", texture);
01170         return WINED3DERR_INVALIDCALL;
01171     }
01172 
01173     /* Calculate levels for mip mapping. */
01174     if (usage & WINED3DUSAGE_AUTOGENMIPMAP)
01175     {
01176         if (!gl_info->supported[SGIS_GENERATE_MIPMAP])
01177         {
01178             WARN("No mipmap generation support, returning D3DERR_INVALIDCALL.\n");
01179             return WINED3DERR_INVALIDCALL;
01180         }
01181 
01182         if (levels > 1)
01183         {
01184             WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL.\n");
01185             return WINED3DERR_INVALIDCALL;
01186         }
01187 
01188         levels = 1;
01189     }
01190     else if (!levels)
01191     {
01192         levels = wined3d_log2i(max(max(width, height), depth)) + 1;
01193         TRACE("Calculated levels = %u.\n", levels);
01194     }
01195 
01196     hr = wined3d_texture_init(texture, &texture3d_ops, 1, levels,
01197             WINED3D_RTYPE_VOLUME_TEXTURE, device, usage, format, pool,
01198             parent, parent_ops, &texture3d_resource_ops);
01199     if (FAILED(hr))
01200     {
01201         WARN("Failed to initialize texture, returning %#x.\n", hr);
01202         return hr;
01203     }
01204 
01205     /* Is NP2 support for volumes needed? */
01206     texture->pow2_matrix[0] = 1.0f;
01207     texture->pow2_matrix[5] = 1.0f;
01208     texture->pow2_matrix[10] = 1.0f;
01209     texture->pow2_matrix[15] = 1.0f;
01210     texture->target = GL_TEXTURE_3D;
01211 
01212     /* Generate all the surfaces. */
01213     tmp_w = width;
01214     tmp_h = height;
01215     tmp_d = depth;
01216 
01217     for (i = 0; i < texture->level_count; ++i)
01218     {
01219         struct wined3d_volume *volume;
01220 
01221         /* Create the volume. */
01222         hr = device->device_parent->ops->create_volume(device->device_parent, parent,
01223                 tmp_w, tmp_h, tmp_d, format_id, pool, usage, &volume);
01224         if (FAILED(hr))
01225         {
01226             ERR("Creating a volume for the volume texture failed, hr %#x.\n", hr);
01227             wined3d_texture_cleanup(texture);
01228             return hr;
01229         }
01230 
01231         /* Set its container to this texture. */
01232         volume_set_container(volume, texture);
01233         texture->sub_resources[i] = &volume->resource;
01234 
01235         /* Calculate the next mipmap level. */
01236         tmp_w = max(1, tmp_w >> 1);
01237         tmp_h = max(1, tmp_h >> 1);
01238         tmp_d = max(1, tmp_d >> 1);
01239     }
01240 
01241     return WINED3D_OK;
01242 }
01243 
01244 HRESULT CDECL wined3d_texture_create_2d(struct wined3d_device *device, UINT width, UINT height,
01245         UINT level_count, DWORD usage, enum wined3d_format_id format_id, enum wined3d_pool pool, void *parent,
01246         const struct wined3d_parent_ops *parent_ops, struct wined3d_texture **texture)
01247 {
01248     struct wined3d_texture *object;
01249     HRESULT hr;
01250 
01251     TRACE("device %p, width %u, height %u, level_count %u, usage %#x\n",
01252             device, width, height, level_count, usage);
01253     TRACE("format %s, pool %#x, parent %p, parent_ops %p, texture %p.\n",
01254             debug_d3dformat(format_id), pool, parent, parent_ops, texture);
01255 
01256     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
01257     if (!object)
01258     {
01259         ERR("Out of memory.\n");
01260         *texture = NULL;
01261         return WINED3DERR_OUTOFVIDEOMEMORY;
01262     }
01263 
01264     hr = texture_init(object, width, height, level_count,
01265             device, usage, format_id, pool, parent, parent_ops);
01266     if (FAILED(hr))
01267     {
01268         WARN("Failed to initialize texture, returning %#x.\n", hr);
01269         HeapFree(GetProcessHeap(), 0, object);
01270         *texture = NULL;
01271         return hr;
01272     }
01273 
01274     TRACE("Created texture %p.\n", object);
01275     *texture = object;
01276 
01277     return WINED3D_OK;
01278 }
01279 
01280 HRESULT CDECL wined3d_texture_create_3d(struct wined3d_device *device, UINT width, UINT height, UINT depth,
01281         UINT level_count, DWORD usage, enum wined3d_format_id format_id, enum wined3d_pool pool, void *parent,
01282         const struct wined3d_parent_ops *parent_ops, struct wined3d_texture **texture)
01283 {
01284     struct wined3d_texture *object;
01285     HRESULT hr;
01286 
01287     TRACE("device %p, width %u, height %u, depth %u, level_count %u, usage %#x\n",
01288             device, width, height, depth, level_count, usage);
01289     TRACE("format %s, pool %#x, parent %p, parent_ops %p, texture %p.\n",
01290             debug_d3dformat(format_id), pool, parent, parent_ops, texture);
01291 
01292     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
01293     if (!object)
01294     {
01295         ERR("Out of memory\n");
01296         *texture = NULL;
01297         return WINED3DERR_OUTOFVIDEOMEMORY;
01298     }
01299 
01300     hr = volumetexture_init(object, width, height, depth, level_count,
01301             device, usage, format_id, pool, parent, parent_ops);
01302     if (FAILED(hr))
01303     {
01304         WARN("Failed to initialize volumetexture, returning %#x\n", hr);
01305         HeapFree(GetProcessHeap(), 0, object);
01306         *texture = NULL;
01307         return hr;
01308     }
01309 
01310     TRACE("Created texture %p.\n", object);
01311     *texture = object;
01312 
01313     return WINED3D_OK;
01314 }
01315 
01316 HRESULT CDECL wined3d_texture_create_cube(struct wined3d_device *device, UINT edge_length,
01317         UINT level_count, DWORD usage, enum wined3d_format_id format_id, enum wined3d_pool pool, void *parent,
01318         const struct wined3d_parent_ops *parent_ops, struct wined3d_texture **texture)
01319 {
01320     struct wined3d_texture *object;
01321     HRESULT hr;
01322 
01323     TRACE("device %p, edge_length %u, level_count %u, usage %#x\n",
01324             device, edge_length, level_count, usage);
01325     TRACE("format %s, pool %#x, parent %p, parent_ops %p, texture %p.\n",
01326             debug_d3dformat(format_id), pool, parent, parent_ops, texture);
01327 
01328     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
01329     if (!object)
01330     {
01331         ERR("Out of memory\n");
01332         *texture = NULL;
01333         return WINED3DERR_OUTOFVIDEOMEMORY;
01334     }
01335 
01336     hr = cubetexture_init(object, edge_length, level_count,
01337             device, usage, format_id, pool, parent, parent_ops);
01338     if (FAILED(hr))
01339     {
01340         WARN("Failed to initialize cubetexture, returning %#x\n", hr);
01341         HeapFree(GetProcessHeap(), 0, object);
01342         *texture = NULL;
01343         return hr;
01344     }
01345 
01346     TRACE("Created texture %p.\n", object);
01347     *texture = object;
01348 
01349     return WINED3D_OK;
01350 }

Generated on Sun May 27 2012 04:22:08 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.