wined3d: Introduce texture_init() to handle most of the 2D texture initialization.
[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, device->lastActiveRenderTarget, 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 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     if (texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING)
201     {
202         texture->baseTexture.minMipLookup = minMipLookup;
203         texture->baseTexture.magLookup = magLookup;
204     }
205     else
206     {
207         texture->baseTexture.minMipLookup = minMipLookup_noFilter;
208         texture->baseTexture.magLookup = magLookup_noFilter;
209     }
210
211     /* Precalculated scaling for 'faked' non power of two texture coords.
212      * Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
213      * is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
214      * doesn't work in combination with ARB_TEXTURE_RECTANGLE. */
215     if (GL_SUPPORT(WINE_NORMALIZED_TEXRECT) && (width != pow2_width || height != pow2_height))
216     {
217         texture->baseTexture.pow2Matrix[0] = 1.0;
218         texture->baseTexture.pow2Matrix[5] = 1.0;
219         texture->baseTexture.pow2Matrix[10] = 1.0;
220         texture->baseTexture.pow2Matrix[15] = 1.0;
221         texture->target = GL_TEXTURE_2D;
222         texture->cond_np2 = TRUE;
223         texture->baseTexture.minMipLookup = minMipLookup_noFilter;
224     }
225     else if (GL_SUPPORT(ARB_TEXTURE_RECTANGLE) && (width != pow2_width || height != pow2_height)
226             && !((format_desc->format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE)
227             && (wined3d_settings.rendertargetlock_mode == RTL_READTEX
228             || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
229     {
230         if ((width != 1) || (height != 1)) texture->baseTexture.pow2Matrix_identity = FALSE;
231
232         texture->baseTexture.pow2Matrix[0] = (float)width;
233         texture->baseTexture.pow2Matrix[5] = (float)height;
234         texture->baseTexture.pow2Matrix[10] = 1.0;
235         texture->baseTexture.pow2Matrix[15] = 1.0;
236         texture->target = GL_TEXTURE_RECTANGLE_ARB;
237         texture->cond_np2 = TRUE;
238         texture->baseTexture.minMipLookup = minMipLookup_noFilter;
239     }
240     else
241     {
242         if ((width != pow2_width) || (height != pow2_height))
243         {
244             texture->baseTexture.pow2Matrix_identity = FALSE;
245             texture->baseTexture.pow2Matrix[0] = (((float)width) / ((float)pow2_width));
246             texture->baseTexture.pow2Matrix[5] = (((float)height) / ((float)pow2_height));
247         }
248         else
249         {
250             texture->baseTexture.pow2Matrix[0] = 1.0;
251             texture->baseTexture.pow2Matrix[5] = 1.0;
252         }
253
254         texture->baseTexture.pow2Matrix[10] = 1.0;
255         texture->baseTexture.pow2Matrix[15] = 1.0;
256         texture->target = GL_TEXTURE_2D;
257         texture->cond_np2 = FALSE;
258     }
259     TRACE("xf(%f) yf(%f)\n", texture->baseTexture.pow2Matrix[0], texture->baseTexture.pow2Matrix[5]);
260
261     /* Generate all the surfaces. */
262     tmp_w = width;
263     tmp_h = height;
264     for (i = 0; i < texture->baseTexture.levels; ++i)
265     {
266         /* Use the callback to create the texture surface. */
267         hr = IWineD3DDeviceParent_CreateSurface(device->device_parent, parent, tmp_w, tmp_h, format_desc->format,
268                 usage, pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &texture->surfaces[i]);
269         if (FAILED(hr) || ((IWineD3DSurfaceImpl *)texture->surfaces[i])->Flags & SFLAG_OVERSIZE)
270         {
271             FIXME("Failed to create surface %p, hr %#x\n", texture, hr);
272             texture->surfaces[i] = NULL;
273             texture_cleanup(texture, D3DCB_DefaultDestroySurface);
274             return hr;
275         }
276
277         IWineD3DSurface_SetContainer(texture->surfaces[i], (IWineD3DBase *)texture);
278         TRACE("Created surface level %u @ %p.\n", i, texture->surfaces[i]);
279         surface_set_texture_target(texture->surfaces[i], texture->target);
280         /* Calculate the next mipmap level. */
281         tmp_w = max(1, tmp_w >> 1);
282         tmp_h = max(1, tmp_h >> 1);
283     }
284     texture->baseTexture.internal_preload = texture_internal_preload;
285
286     return WINED3D_OK;
287 }
288
289 #undef GLINFO_LOCATION
290
291 /* *******************************************
292    IWineD3DTexture IUnknown parts follow
293    ******************************************* */
294
295 #define GLINFO_LOCATION This->resource.wineD3DDevice->adapter->gl_info
296
297 static HRESULT WINAPI IWineD3DTextureImpl_QueryInterface(IWineD3DTexture *iface, REFIID riid, LPVOID *ppobj)
298 {
299     IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface;
300     TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
301     if (IsEqualGUID(riid, &IID_IUnknown)
302         || IsEqualGUID(riid, &IID_IWineD3DBase)
303         || IsEqualGUID(riid, &IID_IWineD3DResource)
304         || IsEqualGUID(riid, &IID_IWineD3DBaseTexture)
305         || IsEqualGUID(riid, &IID_IWineD3DTexture)){
306         IUnknown_AddRef(iface);
307         *ppobj = This;
308         return WINED3D_OK;
309     }
310     *ppobj = NULL;
311     return E_NOINTERFACE;
312 }
313
314 static ULONG WINAPI IWineD3DTextureImpl_AddRef(IWineD3DTexture *iface) {
315     IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface;
316     TRACE("(%p) : AddRef increasing from %d\n", This, This->resource.ref);
317     return InterlockedIncrement(&This->resource.ref);
318 }
319
320 static ULONG WINAPI IWineD3DTextureImpl_Release(IWineD3DTexture *iface) {
321     IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface;
322     ULONG ref;
323     TRACE("(%p) : Releasing from %d\n", This, This->resource.ref);
324     ref = InterlockedDecrement(&This->resource.ref);
325     if (ref == 0) {
326         IWineD3DTexture_Destroy(iface, D3DCB_DefaultDestroySurface);
327     }
328     return ref;
329 }
330
331
332 /* ****************************************************
333    IWineD3DTexture IWineD3DResource parts follow
334    **************************************************** */
335 static HRESULT WINAPI IWineD3DTextureImpl_GetDevice(IWineD3DTexture *iface, IWineD3DDevice** ppDevice) {
336     return resource_get_device((IWineD3DResource *)iface, ppDevice);
337 }
338
339 static HRESULT WINAPI IWineD3DTextureImpl_SetPrivateData(IWineD3DTexture *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
340     return resource_set_private_data((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
341 }
342
343 static HRESULT WINAPI IWineD3DTextureImpl_GetPrivateData(IWineD3DTexture *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
344     return resource_get_private_data((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
345 }
346
347 static HRESULT WINAPI IWineD3DTextureImpl_FreePrivateData(IWineD3DTexture *iface, REFGUID refguid) {
348     return resource_free_private_data((IWineD3DResource *)iface, refguid);
349 }
350
351 static DWORD WINAPI IWineD3DTextureImpl_SetPriority(IWineD3DTexture *iface, DWORD PriorityNew) {
352     return resource_set_priority((IWineD3DResource *)iface, PriorityNew);
353 }
354
355 static DWORD WINAPI IWineD3DTextureImpl_GetPriority(IWineD3DTexture *iface) {
356     return resource_get_priority((IWineD3DResource *)iface);
357 }
358
359 static void WINAPI IWineD3DTextureImpl_PreLoad(IWineD3DTexture *iface) {
360     texture_internal_preload((IWineD3DBaseTexture *) iface, SRGB_ANY);
361 }
362
363 static void WINAPI IWineD3DTextureImpl_UnLoad(IWineD3DTexture *iface) {
364     unsigned int i;
365     IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface;
366     TRACE("(%p)\n", This);
367
368     /* Unload all the surfaces and reset the texture name. If UnLoad was called on the
369      * surface before, this one will be a NOP and vice versa. Unloading an unloaded
370      * surface is fine
371      */
372     for (i = 0; i < This->baseTexture.levels; i++) {
373         IWineD3DSurface_UnLoad(This->surfaces[i]);
374         surface_set_texture_name(This->surfaces[i], 0, FALSE); /* Delete rgb name */
375         surface_set_texture_name(This->surfaces[i], 0, TRUE); /* delete srgb name */
376     }
377
378     basetexture_unload((IWineD3DBaseTexture *)iface);
379 }
380
381 static WINED3DRESOURCETYPE WINAPI IWineD3DTextureImpl_GetType(IWineD3DTexture *iface) {
382     return resource_get_type((IWineD3DResource *)iface);
383 }
384
385 static HRESULT WINAPI IWineD3DTextureImpl_GetParent(IWineD3DTexture *iface, IUnknown **pParent) {
386     return resource_get_parent((IWineD3DResource *)iface, pParent);
387 }
388
389 /* ******************************************************
390    IWineD3DTexture IWineD3DBaseTexture parts follow
391    ****************************************************** */
392 static DWORD WINAPI IWineD3DTextureImpl_SetLOD(IWineD3DTexture *iface, DWORD LODNew) {
393     return basetexture_set_lod((IWineD3DBaseTexture *)iface, LODNew);
394 }
395
396 static DWORD WINAPI IWineD3DTextureImpl_GetLOD(IWineD3DTexture *iface) {
397     return basetexture_get_lod((IWineD3DBaseTexture *)iface);
398 }
399
400 static DWORD WINAPI IWineD3DTextureImpl_GetLevelCount(IWineD3DTexture *iface) {
401     return basetexture_get_level_count((IWineD3DBaseTexture *)iface);
402 }
403
404 static HRESULT WINAPI IWineD3DTextureImpl_SetAutoGenFilterType(IWineD3DTexture *iface, WINED3DTEXTUREFILTERTYPE FilterType) {
405   return basetexture_set_autogen_filter_type((IWineD3DBaseTexture *)iface, FilterType);
406 }
407
408 static WINED3DTEXTUREFILTERTYPE WINAPI IWineD3DTextureImpl_GetAutoGenFilterType(IWineD3DTexture *iface) {
409   return basetexture_get_autogen_filter_type((IWineD3DBaseTexture *)iface);
410 }
411
412 static void WINAPI IWineD3DTextureImpl_GenerateMipSubLevels(IWineD3DTexture *iface) {
413     basetexture_generate_mipmaps((IWineD3DBaseTexture *)iface);
414 }
415
416 /* Internal function, No d3d mapping */
417 static BOOL WINAPI IWineD3DTextureImpl_SetDirty(IWineD3DTexture *iface, BOOL dirty) {
418     return basetexture_set_dirty((IWineD3DBaseTexture *)iface, dirty);
419 }
420
421 static BOOL WINAPI IWineD3DTextureImpl_GetDirty(IWineD3DTexture *iface) {
422     return basetexture_get_dirty((IWineD3DBaseTexture *)iface);
423 }
424
425 static HRESULT WINAPI IWineD3DTextureImpl_BindTexture(IWineD3DTexture *iface, BOOL srgb) {
426     IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface;
427     BOOL set_gl_texture_desc;
428     HRESULT hr;
429
430     TRACE("(%p) : relay to BaseTexture\n", This);
431
432     hr = basetexture_bind((IWineD3DBaseTexture *)iface, srgb, &set_gl_texture_desc);
433     if (set_gl_texture_desc && SUCCEEDED(hr)) {
434         UINT i;
435         for (i = 0; i < This->baseTexture.levels; ++i) {
436             if(This->baseTexture.is_srgb) {
437                 surface_set_texture_name(This->surfaces[i], This->baseTexture.srgbTextureName, TRUE);
438             } else {
439                 surface_set_texture_name(This->surfaces[i], This->baseTexture.textureName, FALSE);
440             }
441         }
442         /* Conditinal non power of two textures use a different clamping default. If we're using the GL_WINE_normalized_texrect
443          * partial driver emulation, we're dealing with a GL_TEXTURE_2D texture which has the address mode set to repeat - something
444          * that prevents us from hitting the accelerated codepath. Thus manually set the GL state. The same applies to filtering.
445          * Even if the texture has only one mip level, the default LINEAR_MIPMAP_LINEAR filter causes a SW fallback on macos.
446          */
447         if(IWineD3DBaseTexture_IsCondNP2(iface)) {
448             ENTER_GL();
449             glTexParameteri(IWineD3DTexture_GetTextureDimensions(iface), GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
450             checkGLcall("glTexParameteri(dimension, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)");
451             glTexParameteri(IWineD3DTexture_GetTextureDimensions(iface), GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
452             checkGLcall("glTexParameteri(dimension, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)");
453             glTexParameteri(IWineD3DTexture_GetTextureDimensions(iface), GL_TEXTURE_MIN_FILTER, GL_NEAREST);
454             checkGLcall("glTexParameteri(dimension, GL_TEXTURE_MIN_FILTER, GL_NEAREST)");
455             glTexParameteri(IWineD3DTexture_GetTextureDimensions(iface), GL_TEXTURE_MAG_FILTER, GL_NEAREST);
456             checkGLcall("glTexParameteri(dimension, GL_TEXTURE_MAG_FILTER, GL_NEAREST)");
457             LEAVE_GL();
458             This->baseTexture.states[WINED3DTEXSTA_ADDRESSU]      = WINED3DTADDRESS_CLAMP;
459             This->baseTexture.states[WINED3DTEXSTA_ADDRESSV]      = WINED3DTADDRESS_CLAMP;
460             This->baseTexture.states[WINED3DTEXSTA_MAGFILTER]     = WINED3DTEXF_POINT;
461             This->baseTexture.states[WINED3DTEXSTA_MINFILTER]     = WINED3DTEXF_POINT;
462             This->baseTexture.states[WINED3DTEXSTA_MIPFILTER]     = WINED3DTEXF_NONE;
463         }
464     }
465
466     return hr;
467 }
468
469 static UINT WINAPI IWineD3DTextureImpl_GetTextureDimensions(IWineD3DTexture *iface) {
470     IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface;
471     TRACE("(%p)\n", This);
472
473     return This->target;
474 }
475
476 static BOOL WINAPI IWineD3DTextureImpl_IsCondNP2(IWineD3DTexture *iface) {
477     IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface;
478     TRACE("(%p)\n", This);
479
480     return This->cond_np2;
481 }
482
483 /* *******************************************
484    IWineD3DTexture IWineD3DTexture parts follow
485    ******************************************* */
486 static void WINAPI IWineD3DTextureImpl_Destroy(IWineD3DTexture *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroySurface) {
487     IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface;
488
489     texture_cleanup(This, D3DCB_DestroySurface);
490     /* free the object */
491     HeapFree(GetProcessHeap(), 0, This);
492 }
493
494 static HRESULT WINAPI IWineD3DTextureImpl_GetLevelDesc(IWineD3DTexture *iface, UINT Level, WINED3DSURFACE_DESC* pDesc) {
495     IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface;
496
497     if (Level < This->baseTexture.levels) {
498         TRACE("(%p) Level (%d)\n", This, Level);
499         return IWineD3DSurface_GetDesc(This->surfaces[Level], pDesc);
500     }
501     WARN("(%p) level(%d) overflow Levels(%d)\n", This, Level, This->baseTexture.levels);
502     return WINED3DERR_INVALIDCALL;
503 }
504
505 static HRESULT WINAPI IWineD3DTextureImpl_GetSurfaceLevel(IWineD3DTexture *iface, UINT Level, IWineD3DSurface** ppSurfaceLevel) {
506     IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface;
507     HRESULT hr = WINED3DERR_INVALIDCALL;
508
509     if (Level < This->baseTexture.levels) {
510         *ppSurfaceLevel = This->surfaces[Level];
511         IWineD3DSurface_AddRef(This->surfaces[Level]);
512         hr = WINED3D_OK;
513         TRACE("(%p) : returning %p for level %d\n", This, *ppSurfaceLevel, Level);
514     }
515     if (WINED3D_OK != hr) {
516         WARN("(%p) level(%d) overflow Levels(%d)\n", This, Level, This->baseTexture.levels);
517         *ppSurfaceLevel = NULL; /* Just to be on the safe side.. */
518     }
519     return hr;
520 }
521
522 static HRESULT WINAPI IWineD3DTextureImpl_LockRect(IWineD3DTexture *iface, UINT Level, WINED3DLOCKED_RECT *pLockedRect,
523                                             CONST RECT *pRect, DWORD Flags) {
524     IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface;
525     HRESULT hr = WINED3DERR_INVALIDCALL;
526
527     if (Level < This->baseTexture.levels) {
528         hr = IWineD3DSurface_LockRect(This->surfaces[Level], pLockedRect, pRect, Flags);
529     }
530     if (WINED3D_OK == hr) {
531         TRACE("(%p) Level (%d) success\n", This, Level);
532     } else {
533         WARN("(%p) level(%d) overflow Levels(%d)\n", This, Level, This->baseTexture.levels);
534     }
535
536     return hr;
537 }
538
539 static HRESULT WINAPI IWineD3DTextureImpl_UnlockRect(IWineD3DTexture *iface, UINT Level) {
540    IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface;
541     HRESULT hr = WINED3DERR_INVALIDCALL;
542
543     if (Level < This->baseTexture.levels) {
544         hr = IWineD3DSurface_UnlockRect(This->surfaces[Level]);
545     }
546     if ( WINED3D_OK == hr) {
547         TRACE("(%p) Level (%d) success\n", This, Level);
548     } else {
549         WARN("(%p) level(%d) overflow Levels(%d)\n", This, Level, This->baseTexture.levels);
550     }
551     return hr;
552 }
553
554 static HRESULT WINAPI IWineD3DTextureImpl_AddDirtyRect(IWineD3DTexture *iface, CONST RECT* pDirtyRect) {
555     IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface;
556     This->baseTexture.dirty = TRUE;
557     This->baseTexture.srgbDirty = TRUE;
558     TRACE("(%p) : dirtyfication of surface Level (0)\n", This);
559     surface_add_dirty_rect(This->surfaces[0], pDirtyRect);
560
561     return WINED3D_OK;
562 }
563
564 const IWineD3DTextureVtbl IWineD3DTexture_Vtbl =
565 {
566     /* IUnknown */
567     IWineD3DTextureImpl_QueryInterface,
568     IWineD3DTextureImpl_AddRef,
569     IWineD3DTextureImpl_Release,
570     /* IWineD3DResource */
571     IWineD3DTextureImpl_GetParent,
572     IWineD3DTextureImpl_GetDevice,
573     IWineD3DTextureImpl_SetPrivateData,
574     IWineD3DTextureImpl_GetPrivateData,
575     IWineD3DTextureImpl_FreePrivateData,
576     IWineD3DTextureImpl_SetPriority,
577     IWineD3DTextureImpl_GetPriority,
578     IWineD3DTextureImpl_PreLoad,
579     IWineD3DTextureImpl_UnLoad,
580     IWineD3DTextureImpl_GetType,
581     /* IWineD3DBaseTexture */
582     IWineD3DTextureImpl_SetLOD,
583     IWineD3DTextureImpl_GetLOD,
584     IWineD3DTextureImpl_GetLevelCount,
585     IWineD3DTextureImpl_SetAutoGenFilterType,
586     IWineD3DTextureImpl_GetAutoGenFilterType,
587     IWineD3DTextureImpl_GenerateMipSubLevels,
588     IWineD3DTextureImpl_SetDirty,
589     IWineD3DTextureImpl_GetDirty,
590     IWineD3DTextureImpl_BindTexture,
591     IWineD3DTextureImpl_GetTextureDimensions,
592     IWineD3DTextureImpl_IsCondNP2,
593     /* IWineD3DTexture */
594     IWineD3DTextureImpl_Destroy,
595     IWineD3DTextureImpl_GetLevelDesc,
596     IWineD3DTextureImpl_GetSurfaceLevel,
597     IWineD3DTextureImpl_LockRect,
598     IWineD3DTextureImpl_UnlockRect,
599     IWineD3DTextureImpl_AddDirtyRect
600 };