shdocvw: Support URLs passed by reference in WebBrowser_Navigate2.
[wine] / dlls / wined3d / texture.c
1 /*
2  * IWineD3DTexture implementation
3  *
4  * Copyright 2002-2005 Jason Edmeades
5  * Copyright 2002-2005 Raphael Junqueira
6  * Copyright 2005 Oliver Stieber
7  * Copyright 2007-2008 Stefan Dösinger for CodeWeavers
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23
24 #include "config.h"
25 #include "wined3d_private.h"
26
27 WINE_DEFAULT_DEBUG_CHANNEL(d3d_texture);
28
29 #define GLINFO_LOCATION (*gl_info)
30
31 static void texture_internal_preload(IWineD3DBaseTexture *iface, enum WINED3DSRGB srgb)
32 {
33     /* Override the IWineD3DResource PreLoad method. */
34     IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface;
35     IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
36     unsigned int i;
37     BOOL srgb_mode;
38     BOOL *dirty;
39
40     TRACE("(%p) : About to load texture.\n", This);
41
42     switch (srgb)
43     {
44         case SRGB_RGB:
45             srgb_mode = FALSE;
46             break;
47
48         case SRGB_BOTH:
49             texture_internal_preload(iface, SRGB_RGB);
50             /* Fallthrough */
51
52         case SRGB_SRGB:
53             srgb_mode = TRUE;
54             break;
55
56         default:
57             srgb_mode = This->baseTexture.is_srgb;
58             break;
59     }
60     dirty = srgb_mode ? &This->baseTexture.srgbDirty : &This->baseTexture.dirty;
61
62     if (!device->isInDraw)
63     {
64         /* ActivateContext sets isInDraw to TRUE when loading a pbuffer into a texture,
65          * thus no danger of recursive calls. */
66         ActivateContext(device, NULL, CTXUSAGE_RESOURCELOAD);
67     }
68
69     if (This->resource.format_desc->format == WINED3DFMT_P8
70             || This->resource.format_desc->format == WINED3DFMT_A8P8)
71     {
72         for (i = 0; i < This->baseTexture.levels; ++i)
73         {
74             if (palette9_changed((IWineD3DSurfaceImpl *)This->surfaces[i]))
75             {
76                 TRACE("Reloading surface because the d3d8/9 palette was changed.\n");
77                 /* TODO: This is not necessarily needed with hw palettized texture support. */
78                 IWineD3DSurface_LoadLocation(This->surfaces[i], SFLAG_INSYSMEM, NULL);
79                 /* Make sure the texture is reloaded because of the palette change, this kills performance though :( */
80                 IWineD3DSurface_ModifyLocation(This->surfaces[i], SFLAG_INTEXTURE, FALSE);
81             }
82         }
83     }
84
85     /* If the texture is marked dirty or the srgb sampler setting has changed
86      * since the last load then reload the surfaces. */
87     if (*dirty)
88     {
89         for (i = 0; i < This->baseTexture.levels; ++i)
90         {
91             IWineD3DSurface_LoadTexture(This->surfaces[i], srgb_mode);
92         }
93     }
94     else
95     {
96         TRACE("(%p) Texture not dirty, nothing to do.\n", iface);
97     }
98
99     /* No longer dirty. */
100     *dirty = FALSE;
101 }
102
103 static void texture_cleanup(IWineD3DTextureImpl *This, D3DCB_DESTROYSURFACEFN surface_destroy_cb)
104 {
105     unsigned int i;
106
107     TRACE("(%p) : Cleaning up\n", This);
108
109     for (i = 0; i < This->baseTexture.levels; ++i)
110     {
111         if (This->surfaces[i])
112         {
113             /* Clean out the texture name we gave to the surface so that the
114              * surface doesn't try and release it */
115             surface_set_texture_name(This->surfaces[i], 0, TRUE);
116             surface_set_texture_name(This->surfaces[i], 0, FALSE);
117             surface_set_texture_target(This->surfaces[i], 0);
118             IWineD3DSurface_SetContainer(This->surfaces[i], 0);
119             surface_destroy_cb(This->surfaces[i]);
120         }
121     }
122
123     TRACE("(%p) : Cleaning up base texture\n", This);
124     basetexture_cleanup((IWineD3DBaseTexture *)This);
125 }
126
127 HRESULT texture_init(IWineD3DTextureImpl *texture, UINT width, UINT height, UINT levels,
128         IWineD3DDeviceImpl *device, DWORD usage, WINED3DFORMAT format, WINED3DPOOL pool, IUnknown *parent)
129 {
130     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
131     const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(format, gl_info);
132     UINT pow2_width, pow2_height;
133     UINT tmp_w, tmp_h;
134     unsigned int i;
135     HRESULT hr;
136
137     /* TODO: It should only be possible to create textures for formats
138      * that are reported as supported. */
139     if (WINED3DFMT_UNKNOWN >= format)
140     {
141         WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN.\n", texture);
142         return WINED3DERR_INVALIDCALL;
143     }
144
145     /* Non-power2 support. */
146     if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO))
147     {
148         pow2_width = width;
149         pow2_height = height;
150     }
151     else
152     {
153         /* Find the nearest pow2 match. */
154         pow2_width = pow2_height = 1;
155         while (pow2_width < width) pow2_width <<= 1;
156         while (pow2_height < height) pow2_height <<= 1;
157
158         if (pow2_width != width || pow2_height != height)
159         {
160             if (levels > 1)
161             {
162                 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support.\n");
163                 return WINED3DERR_INVALIDCALL;
164             }
165             levels = 1;
166         }
167     }
168
169     /* Calculate levels for mip mapping. */
170     if (usage & WINED3DUSAGE_AUTOGENMIPMAP)
171     {
172         if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
173         {
174             WARN("No mipmap generation support, returning WINED3DERR_INVALIDCALL.\n");
175             return WINED3DERR_INVALIDCALL;
176         }
177
178         if (levels > 1)
179         {
180             WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning WINED3DERR_INVALIDCALL.\n");
181             return WINED3DERR_INVALIDCALL;
182         }
183
184         levels = 1;
185     }
186     else if (!levels)
187     {
188         levels = wined3d_log2i(max(width, height)) + 1;
189         TRACE("Calculated levels = %u.\n", levels);
190     }
191
192     hr = basetexture_init((IWineD3DBaseTextureImpl *)texture, levels,
193             WINED3DRTYPE_TEXTURE, device, 0, usage, format_desc, pool, parent);
194     if (FAILED(hr))
195     {
196         WARN("Failed to initialize basetexture, returning %#x.\n", hr);
197         return hr;
198     }
199
200     /* Precalculated scaling for 'faked' non power of two texture coords.
201      * Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
202      * is used in combination with texture uploads (RTL_READTEX). The reason is that EXT_PALETTED_TEXTURE
203      * doesn't work in combination with ARB_TEXTURE_RECTANGLE. */
204     if (GL_SUPPORT(WINE_NORMALIZED_TEXRECT) && (width != pow2_width || height != pow2_height))
205     {
206         texture->baseTexture.pow2Matrix[0] = 1.0f;
207         texture->baseTexture.pow2Matrix[5] = 1.0f;
208         texture->baseTexture.pow2Matrix[10] = 1.0f;
209         texture->baseTexture.pow2Matrix[15] = 1.0f;
210         texture->target = GL_TEXTURE_2D;
211         texture->cond_np2 = TRUE;
212         texture->baseTexture.minMipLookup = minMipLookup_noFilter;
213     }
214     else if (GL_SUPPORT(ARB_TEXTURE_RECTANGLE) && (width != pow2_width || height != pow2_height)
215             && !((format_desc->format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE)
216             && (wined3d_settings.rendertargetlock_mode == RTL_READTEX)))
217     {
218         if ((width != 1) || (height != 1)) texture->baseTexture.pow2Matrix_identity = FALSE;
219
220         texture->baseTexture.pow2Matrix[0] = (float)width;
221         texture->baseTexture.pow2Matrix[5] = (float)height;
222         texture->baseTexture.pow2Matrix[10] = 1.0f;
223         texture->baseTexture.pow2Matrix[15] = 1.0f;
224         texture->target = GL_TEXTURE_RECTANGLE_ARB;
225         texture->cond_np2 = TRUE;
226         texture->baseTexture.minMipLookup = minMipLookup_noFilter;
227     }
228     else
229     {
230         if ((width != pow2_width) || (height != pow2_height))
231         {
232             texture->baseTexture.pow2Matrix_identity = FALSE;
233             texture->baseTexture.pow2Matrix[0] = (((float)width) / ((float)pow2_width));
234             texture->baseTexture.pow2Matrix[5] = (((float)height) / ((float)pow2_height));
235         }
236         else
237         {
238             texture->baseTexture.pow2Matrix[0] = 1.0f;
239             texture->baseTexture.pow2Matrix[5] = 1.0f;
240         }
241
242         texture->baseTexture.pow2Matrix[10] = 1.0f;
243         texture->baseTexture.pow2Matrix[15] = 1.0f;
244         texture->target = GL_TEXTURE_2D;
245         texture->cond_np2 = FALSE;
246     }
247     TRACE("xf(%f) yf(%f)\n", texture->baseTexture.pow2Matrix[0], texture->baseTexture.pow2Matrix[5]);
248
249     /* Generate all the surfaces. */
250     tmp_w = width;
251     tmp_h = height;
252     for (i = 0; i < texture->baseTexture.levels; ++i)
253     {
254         /* Use the callback to create the texture surface. */
255         hr = IWineD3DDeviceParent_CreateSurface(device->device_parent, parent, tmp_w, tmp_h, format_desc->format,
256                 usage, pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &texture->surfaces[i]);
257         if (FAILED(hr) || ((IWineD3DSurfaceImpl *)texture->surfaces[i])->Flags & SFLAG_OVERSIZE)
258         {
259             FIXME("Failed to create surface %p, hr %#x\n", texture, hr);
260             texture->surfaces[i] = NULL;
261             texture_cleanup(texture, D3DCB_DefaultDestroySurface);
262             return hr;
263         }
264
265         IWineD3DSurface_SetContainer(texture->surfaces[i], (IWineD3DBase *)texture);
266         TRACE("Created surface level %u @ %p.\n", i, texture->surfaces[i]);
267         surface_set_texture_target(texture->surfaces[i], texture->target);
268         /* Calculate the next mipmap level. */
269         tmp_w = max(1, tmp_w >> 1);
270         tmp_h = max(1, tmp_h >> 1);
271     }
272     texture->baseTexture.internal_preload = texture_internal_preload;
273
274     return WINED3D_OK;
275 }
276
277 #undef GLINFO_LOCATION
278
279 /* *******************************************
280    IWineD3DTexture IUnknown parts follow
281    ******************************************* */
282
283 #define GLINFO_LOCATION This->resource.wineD3DDevice->adapter->gl_info
284
285 static HRESULT WINAPI IWineD3DTextureImpl_QueryInterface(IWineD3DTexture *iface, REFIID riid, LPVOID *ppobj)
286 {
287     IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface;
288     TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
289     if (IsEqualGUID(riid, &IID_IUnknown)
290         || IsEqualGUID(riid, &IID_IWineD3DBase)
291         || IsEqualGUID(riid, &IID_IWineD3DResource)
292         || IsEqualGUID(riid, &IID_IWineD3DBaseTexture)
293         || IsEqualGUID(riid, &IID_IWineD3DTexture)){
294         IUnknown_AddRef(iface);
295         *ppobj = This;
296         return WINED3D_OK;
297     }
298     *ppobj = NULL;
299     return E_NOINTERFACE;
300 }
301
302 static ULONG WINAPI IWineD3DTextureImpl_AddRef(IWineD3DTexture *iface) {
303     IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface;
304     TRACE("(%p) : AddRef increasing from %d\n", This, This->resource.ref);
305     return InterlockedIncrement(&This->resource.ref);
306 }
307
308 static ULONG WINAPI IWineD3DTextureImpl_Release(IWineD3DTexture *iface) {
309     IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface;
310     ULONG ref;
311     TRACE("(%p) : Releasing from %d\n", This, This->resource.ref);
312     ref = InterlockedDecrement(&This->resource.ref);
313     if (ref == 0) {
314         IWineD3DTexture_Destroy(iface, D3DCB_DefaultDestroySurface);
315     }
316     return ref;
317 }
318
319
320 /* ****************************************************
321    IWineD3DTexture IWineD3DResource parts follow
322    **************************************************** */
323 static HRESULT WINAPI IWineD3DTextureImpl_GetDevice(IWineD3DTexture *iface, IWineD3DDevice** ppDevice) {
324     return resource_get_device((IWineD3DResource *)iface, ppDevice);
325 }
326
327 static HRESULT WINAPI IWineD3DTextureImpl_SetPrivateData(IWineD3DTexture *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
328     return resource_set_private_data((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
329 }
330
331 static HRESULT WINAPI IWineD3DTextureImpl_GetPrivateData(IWineD3DTexture *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
332     return resource_get_private_data((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
333 }
334
335 static HRESULT WINAPI IWineD3DTextureImpl_FreePrivateData(IWineD3DTexture *iface, REFGUID refguid) {
336     return resource_free_private_data((IWineD3DResource *)iface, refguid);
337 }
338
339 static DWORD WINAPI IWineD3DTextureImpl_SetPriority(IWineD3DTexture *iface, DWORD PriorityNew) {
340     return resource_set_priority((IWineD3DResource *)iface, PriorityNew);
341 }
342
343 static DWORD WINAPI IWineD3DTextureImpl_GetPriority(IWineD3DTexture *iface) {
344     return resource_get_priority((IWineD3DResource *)iface);
345 }
346
347 static void WINAPI IWineD3DTextureImpl_PreLoad(IWineD3DTexture *iface) {
348     texture_internal_preload((IWineD3DBaseTexture *) iface, SRGB_ANY);
349 }
350
351 static void WINAPI IWineD3DTextureImpl_UnLoad(IWineD3DTexture *iface) {
352     unsigned int i;
353     IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface;
354     TRACE("(%p)\n", This);
355
356     /* Unload all the surfaces and reset the texture name. If UnLoad was called on the
357      * surface before, this one will be a NOP and vice versa. Unloading an unloaded
358      * surface is fine
359      */
360     for (i = 0; i < This->baseTexture.levels; i++) {
361         IWineD3DSurface_UnLoad(This->surfaces[i]);
362         surface_set_texture_name(This->surfaces[i], 0, FALSE); /* Delete rgb name */
363         surface_set_texture_name(This->surfaces[i], 0, TRUE); /* delete srgb name */
364     }
365
366     basetexture_unload((IWineD3DBaseTexture *)iface);
367 }
368
369 static WINED3DRESOURCETYPE WINAPI IWineD3DTextureImpl_GetType(IWineD3DTexture *iface) {
370     return resource_get_type((IWineD3DResource *)iface);
371 }
372
373 static HRESULT WINAPI IWineD3DTextureImpl_GetParent(IWineD3DTexture *iface, IUnknown **pParent) {
374     return resource_get_parent((IWineD3DResource *)iface, pParent);
375 }
376
377 /* ******************************************************
378    IWineD3DTexture IWineD3DBaseTexture parts follow
379    ****************************************************** */
380 static DWORD WINAPI IWineD3DTextureImpl_SetLOD(IWineD3DTexture *iface, DWORD LODNew) {
381     return basetexture_set_lod((IWineD3DBaseTexture *)iface, LODNew);
382 }
383
384 static DWORD WINAPI IWineD3DTextureImpl_GetLOD(IWineD3DTexture *iface) {
385     return basetexture_get_lod((IWineD3DBaseTexture *)iface);
386 }
387
388 static DWORD WINAPI IWineD3DTextureImpl_GetLevelCount(IWineD3DTexture *iface) {
389     return basetexture_get_level_count((IWineD3DBaseTexture *)iface);
390 }
391
392 static HRESULT WINAPI IWineD3DTextureImpl_SetAutoGenFilterType(IWineD3DTexture *iface, WINED3DTEXTUREFILTERTYPE FilterType) {
393   return basetexture_set_autogen_filter_type((IWineD3DBaseTexture *)iface, FilterType);
394 }
395
396 static WINED3DTEXTUREFILTERTYPE WINAPI IWineD3DTextureImpl_GetAutoGenFilterType(IWineD3DTexture *iface) {
397   return basetexture_get_autogen_filter_type((IWineD3DBaseTexture *)iface);
398 }
399
400 static void WINAPI IWineD3DTextureImpl_GenerateMipSubLevels(IWineD3DTexture *iface) {
401     basetexture_generate_mipmaps((IWineD3DBaseTexture *)iface);
402 }
403
404 /* Internal function, No d3d mapping */
405 static BOOL WINAPI IWineD3DTextureImpl_SetDirty(IWineD3DTexture *iface, BOOL dirty) {
406     return basetexture_set_dirty((IWineD3DBaseTexture *)iface, dirty);
407 }
408
409 static BOOL WINAPI IWineD3DTextureImpl_GetDirty(IWineD3DTexture *iface) {
410     return basetexture_get_dirty((IWineD3DBaseTexture *)iface);
411 }
412
413 /* Context activation is done by the caller. */
414 static HRESULT WINAPI IWineD3DTextureImpl_BindTexture(IWineD3DTexture *iface, BOOL srgb) {
415     IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface;
416     BOOL set_gl_texture_desc;
417     HRESULT hr;
418
419     TRACE("(%p) : relay to BaseTexture\n", This);
420
421     hr = basetexture_bind((IWineD3DBaseTexture *)iface, srgb, &set_gl_texture_desc);
422     if (set_gl_texture_desc && SUCCEEDED(hr)) {
423         UINT i;
424         for (i = 0; i < This->baseTexture.levels; ++i) {
425             if(This->baseTexture.is_srgb) {
426                 surface_set_texture_name(This->surfaces[i], This->baseTexture.srgbTextureName, TRUE);
427             } else {
428                 surface_set_texture_name(This->surfaces[i], This->baseTexture.textureName, FALSE);
429             }
430         }
431         /* Conditinal non power of two textures use a different clamping default. If we're using the GL_WINE_normalized_texrect
432          * partial driver emulation, we're dealing with a GL_TEXTURE_2D texture which has the address mode set to repeat - something
433          * that prevents us from hitting the accelerated codepath. Thus manually set the GL state. The same applies to filtering.
434          * Even if the texture has only one mip level, the default LINEAR_MIPMAP_LINEAR filter causes a SW fallback on macos.
435          */
436         if(IWineD3DBaseTexture_IsCondNP2(iface)) {
437             ENTER_GL();
438             glTexParameteri(IWineD3DTexture_GetTextureDimensions(iface), GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
439             checkGLcall("glTexParameteri(dimension, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)");
440             glTexParameteri(IWineD3DTexture_GetTextureDimensions(iface), GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
441             checkGLcall("glTexParameteri(dimension, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)");
442             glTexParameteri(IWineD3DTexture_GetTextureDimensions(iface), GL_TEXTURE_MIN_FILTER, GL_NEAREST);
443             checkGLcall("glTexParameteri(dimension, GL_TEXTURE_MIN_FILTER, GL_NEAREST)");
444             glTexParameteri(IWineD3DTexture_GetTextureDimensions(iface), GL_TEXTURE_MAG_FILTER, GL_NEAREST);
445             checkGLcall("glTexParameteri(dimension, GL_TEXTURE_MAG_FILTER, GL_NEAREST)");
446             LEAVE_GL();
447             This->baseTexture.states[WINED3DTEXSTA_ADDRESSU]      = WINED3DTADDRESS_CLAMP;
448             This->baseTexture.states[WINED3DTEXSTA_ADDRESSV]      = WINED3DTADDRESS_CLAMP;
449             This->baseTexture.states[WINED3DTEXSTA_MAGFILTER]     = WINED3DTEXF_POINT;
450             This->baseTexture.states[WINED3DTEXSTA_MINFILTER]     = WINED3DTEXF_POINT;
451             This->baseTexture.states[WINED3DTEXSTA_MIPFILTER]     = WINED3DTEXF_NONE;
452         }
453     }
454
455     return hr;
456 }
457
458 static UINT WINAPI IWineD3DTextureImpl_GetTextureDimensions(IWineD3DTexture *iface) {
459     IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface;
460     TRACE("(%p)\n", This);
461
462     return This->target;
463 }
464
465 static BOOL WINAPI IWineD3DTextureImpl_IsCondNP2(IWineD3DTexture *iface) {
466     IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface;
467     TRACE("(%p)\n", This);
468
469     return This->cond_np2;
470 }
471
472 /* *******************************************
473    IWineD3DTexture IWineD3DTexture parts follow
474    ******************************************* */
475 static void WINAPI IWineD3DTextureImpl_Destroy(IWineD3DTexture *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroySurface) {
476     IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface;
477
478     texture_cleanup(This, D3DCB_DestroySurface);
479     /* free the object */
480     HeapFree(GetProcessHeap(), 0, This);
481 }
482
483 static HRESULT WINAPI IWineD3DTextureImpl_GetLevelDesc(IWineD3DTexture *iface, UINT Level, WINED3DSURFACE_DESC* pDesc) {
484     IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface;
485
486     if (Level < This->baseTexture.levels) {
487         TRACE("(%p) Level (%d)\n", This, Level);
488         return IWineD3DSurface_GetDesc(This->surfaces[Level], pDesc);
489     }
490     WARN("(%p) level(%d) overflow Levels(%d)\n", This, Level, This->baseTexture.levels);
491     return WINED3DERR_INVALIDCALL;
492 }
493
494 static HRESULT WINAPI IWineD3DTextureImpl_GetSurfaceLevel(IWineD3DTexture *iface, UINT Level, IWineD3DSurface** ppSurfaceLevel) {
495     IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface;
496     HRESULT hr = WINED3DERR_INVALIDCALL;
497
498     if (Level < This->baseTexture.levels) {
499         *ppSurfaceLevel = This->surfaces[Level];
500         IWineD3DSurface_AddRef(This->surfaces[Level]);
501         hr = WINED3D_OK;
502         TRACE("(%p) : returning %p for level %d\n", This, *ppSurfaceLevel, Level);
503     }
504     if (WINED3D_OK != hr) {
505         WARN("(%p) level(%d) overflow Levels(%d)\n", This, Level, This->baseTexture.levels);
506         *ppSurfaceLevel = NULL; /* Just to be on the safe side.. */
507     }
508     return hr;
509 }
510
511 static HRESULT WINAPI IWineD3DTextureImpl_LockRect(IWineD3DTexture *iface, UINT Level, WINED3DLOCKED_RECT *pLockedRect,
512                                             CONST RECT *pRect, DWORD Flags) {
513     IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface;
514     HRESULT hr = WINED3DERR_INVALIDCALL;
515
516     if (Level < This->baseTexture.levels) {
517         hr = IWineD3DSurface_LockRect(This->surfaces[Level], pLockedRect, pRect, Flags);
518     }
519     if (WINED3D_OK == hr) {
520         TRACE("(%p) Level (%d) success\n", This, Level);
521     } else {
522         WARN("(%p) level(%d) overflow Levels(%d)\n", This, Level, This->baseTexture.levels);
523     }
524
525     return hr;
526 }
527
528 static HRESULT WINAPI IWineD3DTextureImpl_UnlockRect(IWineD3DTexture *iface, UINT Level) {
529    IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface;
530     HRESULT hr = WINED3DERR_INVALIDCALL;
531
532     if (Level < This->baseTexture.levels) {
533         hr = IWineD3DSurface_UnlockRect(This->surfaces[Level]);
534     }
535     if ( WINED3D_OK == hr) {
536         TRACE("(%p) Level (%d) success\n", This, Level);
537     } else {
538         WARN("(%p) level(%d) overflow Levels(%d)\n", This, Level, This->baseTexture.levels);
539     }
540     return hr;
541 }
542
543 static HRESULT WINAPI IWineD3DTextureImpl_AddDirtyRect(IWineD3DTexture *iface, CONST RECT* pDirtyRect) {
544     IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface;
545     This->baseTexture.dirty = TRUE;
546     This->baseTexture.srgbDirty = TRUE;
547     TRACE("(%p) : dirtyfication of surface Level (0)\n", This);
548     surface_add_dirty_rect(This->surfaces[0], pDirtyRect);
549
550     return WINED3D_OK;
551 }
552
553 const IWineD3DTextureVtbl IWineD3DTexture_Vtbl =
554 {
555     /* IUnknown */
556     IWineD3DTextureImpl_QueryInterface,
557     IWineD3DTextureImpl_AddRef,
558     IWineD3DTextureImpl_Release,
559     /* IWineD3DResource */
560     IWineD3DTextureImpl_GetParent,
561     IWineD3DTextureImpl_GetDevice,
562     IWineD3DTextureImpl_SetPrivateData,
563     IWineD3DTextureImpl_GetPrivateData,
564     IWineD3DTextureImpl_FreePrivateData,
565     IWineD3DTextureImpl_SetPriority,
566     IWineD3DTextureImpl_GetPriority,
567     IWineD3DTextureImpl_PreLoad,
568     IWineD3DTextureImpl_UnLoad,
569     IWineD3DTextureImpl_GetType,
570     /* IWineD3DBaseTexture */
571     IWineD3DTextureImpl_SetLOD,
572     IWineD3DTextureImpl_GetLOD,
573     IWineD3DTextureImpl_GetLevelCount,
574     IWineD3DTextureImpl_SetAutoGenFilterType,
575     IWineD3DTextureImpl_GetAutoGenFilterType,
576     IWineD3DTextureImpl_GenerateMipSubLevels,
577     IWineD3DTextureImpl_SetDirty,
578     IWineD3DTextureImpl_GetDirty,
579     IWineD3DTextureImpl_BindTexture,
580     IWineD3DTextureImpl_GetTextureDimensions,
581     IWineD3DTextureImpl_IsCondNP2,
582     /* IWineD3DTexture */
583     IWineD3DTextureImpl_Destroy,
584     IWineD3DTextureImpl_GetLevelDesc,
585     IWineD3DTextureImpl_GetSurfaceLevel,
586     IWineD3DTextureImpl_LockRect,
587     IWineD3DTextureImpl_UnlockRect,
588     IWineD3DTextureImpl_AddDirtyRect
589 };