Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygentexture.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
1.7.6.1
|