wined3d: Add device caps to wined3d_types.h.
[wine/multimedia.git] / dlls / wined3d / surface.c
blob362f5b969f7fbf726f2981aad901778c1e402447
1 /*
2 * IWineD3DSurface Implementation
4 * Copyright 2002-2005 Jason Edmeades
5 * Copyright 2002-2003 Raphael Junqueira
6 * Copyright 2004 Christian Costa
7 * Copyright 2005 Oliver Stieber
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "config.h"
25 #include "wine/port.h"
26 #include "wined3d_private.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
29 #define GLINFO_LOCATION ((IWineD3DImpl *)(((IWineD3DDeviceImpl *)This->resource.wineD3DDevice)->wineD3D))->gl_info
31 /* *******************************************
32 IWineD3DSurface IUnknown parts follow
33 ******************************************* */
34 HRESULT WINAPI IWineD3DSurfaceImpl_QueryInterface(IWineD3DSurface *iface, REFIID riid, LPVOID *ppobj)
36 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
37 /* Warn ,but be nice about things */
38 TRACE("(%p)->(%s,%p)\n", This,debugstr_guid(riid),ppobj);
39 if (riid == NULL) {
40 ERR("Probably FIXME: Calling query interface with NULL riid\n");
42 if (IsEqualGUID(riid, &IID_IUnknown)
43 || IsEqualGUID(riid, &IID_IWineD3DBase)
44 || IsEqualGUID(riid, &IID_IWineD3DResource)
45 || IsEqualGUID(riid, &IID_IWineD3DSurface)) {
46 IUnknown_AddRef((IUnknown*)iface);
47 *ppobj = This;
48 return D3D_OK;
50 return E_NOINTERFACE;
53 ULONG WINAPI IWineD3DSurfaceImpl_AddRef(IWineD3DSurface *iface) {
54 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
55 ULONG ref = InterlockedIncrement(&This->resource.ref);
56 TRACE("(%p) : AddRef increasing from %ld\n", This,ref - 1);
57 return ref;
60 ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface) {
61 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
62 ULONG ref = InterlockedDecrement(&This->resource.ref);
63 TRACE("(%p) : Releasing from %ld\n", This, ref + 1);
64 if (ref == 0) {
65 TRACE("(%p) : cleaning up\n", This);
66 if (This->glDescription.textureName != 0) { /* release the openGL texture.. */
67 ENTER_GL();
68 TRACE("Deleting texture %d\n", This->glDescription.textureName);
69 glDeleteTextures(1, &This->glDescription.textureName);
70 LEAVE_GL();
72 IWineD3DResourceImpl_CleanUp((IWineD3DResource *)iface);
74 TRACE("(%p) Released\n", This);
75 HeapFree(GetProcessHeap(), 0, This);
78 return ref;
81 /* ****************************************************
82 IWineD3DSurface IWineD3DResource parts follow
83 **************************************************** */
84 HRESULT WINAPI IWineD3DSurfaceImpl_GetDevice(IWineD3DSurface *iface, IWineD3DDevice** ppDevice) {
85 return IWineD3DResourceImpl_GetDevice((IWineD3DResource *)iface, ppDevice);
88 HRESULT WINAPI IWineD3DSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
89 return IWineD3DResourceImpl_SetPrivateData((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
92 HRESULT WINAPI IWineD3DSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
93 return IWineD3DResourceImpl_GetPrivateData((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
96 HRESULT WINAPI IWineD3DSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid) {
97 return IWineD3DResourceImpl_FreePrivateData((IWineD3DResource *)iface, refguid);
100 DWORD WINAPI IWineD3DSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) {
101 return IWineD3DResourceImpl_SetPriority((IWineD3DResource *)iface, PriorityNew);
104 DWORD WINAPI IWineD3DSurfaceImpl_GetPriority(IWineD3DSurface *iface) {
105 return IWineD3DResourceImpl_GetPriority((IWineD3DResource *)iface);
108 void WINAPI IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface *iface) {
109 /* TODO: re-write the way textures and managed,
110 * use a 'opengl context manager' to manage RenderTarget surfaces
111 ** *********************************************************/
113 /* TODO: check for locks */
114 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
115 IWineD3DBaseTexture *baseTexture = NULL;
116 TRACE("(%p)Checking to see if the container is a base texture\n", This);
117 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == D3D_OK) {
118 TRACE("Passing to conatiner\n");
119 IWineD3DBaseTexture_PreLoad(baseTexture);
120 IWineD3DBaseTexture_Release(baseTexture);
121 } else {
122 TRACE("(%p) : About to load surface\n", This);
123 ENTER_GL();
124 #if 0 /* TODO: context manager support */
125 IWineD3DContextManager_PushState(This->contextManager, GL_TEXTURE_2D, ENABLED, NOW /* make sure the state is applied now */);
126 #endif
127 glEnable(This->glDescription.target);/* make sure texture support is enabled in this context */
128 if (This->glDescription.level == 0 && This->glDescription.textureName == 0) {
129 glGenTextures(1, &This->glDescription.textureName);
130 checkGLcall("glGenTextures");
131 TRACE("Surface %p given name %d\n", This, This->glDescription.textureName);
132 glBindTexture(This->glDescription.target, This->glDescription.textureName);
133 checkGLcall("glBindTexture");
134 IWineD3DSurface_LoadTexture(iface);
135 /* This is where we should be reducing the amount of GLMemoryUsed */
136 } else {
137 if (This->glDescription.level == 0) {
138 glBindTexture(This->glDescription.target, This->glDescription.textureName);
139 checkGLcall("glBindTexture");
140 IWineD3DSurface_LoadTexture(iface);
141 } else if (This->glDescription.textureName != 0) { /* NOTE: the level 0 surface of a mpmapped texture must be loaded first! */
142 /* assume this is a coding error not a real error for now */
143 FIXME("Mipmap surface has a glTexture bound to it!\n");
146 if (This->resource.pool == D3DPOOL_DEFAULT) {
147 /* Tell opengl to try and keep this texture in video ram (well mostly) */
148 GLclampf tmp;
149 tmp = 0.9f;
150 glPrioritizeTextures(1, &This->glDescription.textureName, &tmp);
152 /* TODO: disable texture support, if it wastn't enabled when we entered. */
153 #if 0 /* TODO: context manager support */
154 IWineD3DContextManager_PopState(This->contextManager, GL_TEXTURE_2D, DISABLED,DELAYED
155 /* we don't care when the state is disabled(if atall) */);
156 #endif
157 LEAVE_GL();
159 return;
162 D3DRESOURCETYPE WINAPI IWineD3DSurfaceImpl_GetType(IWineD3DSurface *iface) {
163 TRACE("(%p) : calling resourceimpl_GetType\n", iface);
164 return IWineD3DResourceImpl_GetType((IWineD3DResource *)iface);
167 HRESULT WINAPI IWineD3DSurfaceImpl_GetParent(IWineD3DSurface *iface, IUnknown **pParent) {
168 TRACE("(%p) : calling resourceimpl_GetParent\n", iface);
169 return IWineD3DResourceImpl_GetParent((IWineD3DResource *)iface, pParent);
172 /* ******************************************************
173 IWineD3DSurface IWineD3DSurface parts follow
174 ****************************************************** */
176 HRESULT WINAPI IWineD3DSurfaceImpl_GetContainerParent(IWineD3DSurface* iface, IUnknown **ppContainerParent) {
177 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
179 TRACE("(%p) : ppContainerParent %p)\n", This, ppContainerParent);
181 if (!ppContainerParent) {
182 ERR("(%p) : Called without a valid ppContainerParent.\n", This);
185 if (This->container) {
186 IWineD3DBase_GetParent(This->container, ppContainerParent);
187 if (!ppContainerParent) {
188 /* WineD3D objects should always have a parent */
189 ERR("(%p) : GetParent returned NULL\n", This);
191 IUnknown_Release(*ppContainerParent); /* GetParent adds a reference; we want just the pointer */
192 } else {
193 *ppContainerParent = NULL;
196 return D3D_OK;
199 HRESULT WINAPI IWineD3DSurfaceImpl_GetContainer(IWineD3DSurface* iface, REFIID riid, void** ppContainer) {
200 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
201 IWineD3DBase *container = 0;
203 TRACE("(This %p, riid %s, ppContainer %p)\n", This, debugstr_guid(riid), ppContainer);
205 if (!ppContainer) {
206 ERR("Called without a valid ppContainer.\n");
209 /** From MSDN:
210 * If the surface is created using CreateImageSurface/CreateOffscreenPlainSurface, CreateRenderTarget,
211 * or CreateDepthStencilSurface, the surface is considered stand alone. In this case,
212 * GetContainer will return the Direct3D device used to create the surface.
214 if (This->container) {
215 container = This->container;
216 } else {
217 container = (IWineD3DBase *)This->resource.wineD3DDevice;
220 TRACE("Relaying to QueryInterface\n");
221 return IUnknown_QueryInterface(container, riid, ppContainer);
224 HRESULT WINAPI IWineD3DSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc) {
225 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
227 TRACE("(%p) : copying into %p\n", This, pDesc);
228 if(pDesc->Format != NULL) *(pDesc->Format) = This->resource.format;
229 if(pDesc->Type != NULL) *(pDesc->Type) = This->resource.resourceType;
230 if(pDesc->Usage != NULL) *(pDesc->Usage) = This->resource.usage;
231 if(pDesc->Pool != NULL) *(pDesc->Pool) = This->resource.pool;
232 if(pDesc->Size != NULL) *(pDesc->Size) = This->resource.size; /* dx8 only */
233 if(pDesc->MultiSampleType != NULL) *(pDesc->MultiSampleType) = This->currentDesc.MultiSampleType;
234 if(pDesc->MultiSampleQuality != NULL) *(pDesc->MultiSampleQuality) = This->currentDesc.MultiSampleQuality;
235 if(pDesc->Width != NULL) *(pDesc->Width) = This->currentDesc.Width;
236 if(pDesc->Height != NULL) *(pDesc->Height) = This->currentDesc.Height;
237 return D3D_OK;
240 void WINAPI IWineD3DSurfaceImpl_SetGlTextureDesc(IWineD3DSurface *iface, UINT textureName, int target) {
241 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
242 TRACE("(%p) : setting textureName %u, target %i\n", This, textureName, target);
243 if (This->glDescription.textureName == 0 && textureName != 0) {
244 This->Dirty = TRUE;
245 IWineD3DSurface_AddDirtyRect(iface, NULL);
247 This->glDescription.textureName = textureName;
248 This->glDescription.target = target;
251 void WINAPI IWineD3DSurfaceImpl_GetGlDesc(IWineD3DSurface *iface, glDescriptor **glDescription) {
252 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
253 TRACE("(%p) : returning %p\n", This, &This->glDescription);
254 *glDescription = &This->glDescription;
257 /* TODO: think about moving this down to resource? */
258 const void *WINAPI IWineD3DSurfaceImpl_GetData(IWineD3DSurface *iface) {
259 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
260 /* This should only be called for sysmem textures, it may be a good idea to extend this to all pools at some point in the futture */
261 if (This->resource.pool != D3DPOOL_SYSTEMMEM) {
262 FIXME(" (%p)Attempting to get system memory for a non-system memory texture\n", iface);
264 return (CONST void*)(This->resource.allocatedMemory);
267 HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, D3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
268 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
269 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
270 IWineD3DSwapChainImpl *swapchain = NULL;
271 static UINT messages = 0; /* holds flags to disable fixme messages */
273 /* fixme: should we really lock as such? */
274 if (This->inTexture && This->inPBuffer) {
275 FIXME("Warning: Surface is in texture memory or pbuffer\n");
276 This->inTexture = 0;
277 This->inPBuffer = 0;
280 if (FALSE == This->lockable) {
281 /* Note: UpdateTextures calls CopyRects which calls this routine to populate the
282 texture regions, and since the destination is an unlockable region we need
283 to tolerate this */
284 TRACE("Warning: trying to lock unlockable surf@%p\n", This);
285 /*return D3DERR_INVALIDCALL; */
288 if (This->resource.usage & D3DUSAGE_RENDERTARGET) {
289 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
291 if (swapchain != NULL || iface == myDevice->renderTarget || iface == myDevice->depthStencilBuffer) {
292 if (swapchain != NULL && iface == swapchain->backBuffer) {
293 TRACE("(%p, backBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
294 } else if (swapchain != NULL && iface == swapchain->frontBuffer) {
295 TRACE("(%p, frontBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
296 } else if (iface == myDevice->renderTarget) {
297 TRACE("(%p, renderTarget) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
298 } else if (iface == myDevice->depthStencilBuffer) {
299 TRACE("(%p, stencilBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
302 if (NULL != swapchain) {
303 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
305 swapchain = NULL;
307 } else {
308 TRACE("(%p) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
311 /* DXTn formats don't have exact pitches as they are to the new row of blocks,
312 where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5)
313 ie pitch = (width/4) * bytes per block */
314 if (This->resource.format == WINED3DFMT_DXT1) /* DXT1 is 8 bytes per block */
315 pLockedRect->Pitch = (This->currentDesc.Width >> 2) << 3;
316 else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
317 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) /* DXT2/3/4/5 is 16 bytes per block */
318 pLockedRect->Pitch = (This->currentDesc.Width >> 2) << 4;
319 else {
320 if (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & D3DUSAGE_RENDERTARGET) {
321 /* Front and back buffers are always lockes/unlocked on currentDesc.Width */
322 pLockedRect->Pitch = This->bytesPerPixel * This->currentDesc.Width; /* Bytes / row */
323 } else {
324 pLockedRect->Pitch = This->bytesPerPixel * This->pow2Width;
328 if (NULL == pRect) {
329 pLockedRect->pBits = This->resource.allocatedMemory;
330 This->lockedRect.left = 0;
331 This->lockedRect.top = 0;
332 This->lockedRect.right = This->currentDesc.Width;
333 This->lockedRect.bottom = This->currentDesc.Height;
334 TRACE("Locked Rect (%p) = l %ld, t %ld, r %ld, b %ld\n", &This->lockedRect, This->lockedRect.left, This->lockedRect.top, This->lockedRect.right, This->lockedRect.bottom);
335 } else {
336 TRACE("Lock Rect (%p) = l %ld, t %ld, r %ld, b %ld\n", pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
338 if (This->resource.format == WINED3DFMT_DXT1) { /* DXT1 is half byte per pixel */
339 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
340 } else {
341 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
343 This->lockedRect.left = pRect->left;
344 This->lockedRect.top = pRect->top;
345 This->lockedRect.right = pRect->right;
346 This->lockedRect.bottom = pRect->bottom;
349 if (This->nonpow2) {
350 TRACE("Locking non-power 2 texture\n");
353 if (0 == This->resource.usage || This->resource.usage & D3DUSAGE_DYNAMIC) {
354 /* classic surface TODO: non 2d surfaces?
355 These resources may be POOL_SYSTEMMEM, so they must not access the device */
356 TRACE("locking an ordinarary surface\n");
357 /* Check to see if memory has already been allocated from the surface*/
358 if (NULL == This->resource.allocatedMemory) { /* TODO: check to see if an update has been performed on the surface (an update could just clobber allocatedMemory */
359 /* Non-system memory surfaces */
361 /*Surface has no memory currently allocated to it!*/
362 TRACE("(%p) Locking rect\n" , This);
363 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 , This->pow2Size);
364 if (0 != This->glDescription.textureName) {
365 /* Now I have to copy thing bits back */
366 This->activeLock = TRUE; /* When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory */
367 /* TODO: make activeLock a bit more intelligent, maybe implement a method to purge the texture memory. */
368 ENTER_GL();
370 /* Make sure that the texture is loaded */
371 IWineD3DSurface_PreLoad(iface); /* Make sure there is a texture to bind! */
373 TRACE("(%p) glGetTexImage level(%d), fmt(%d), typ(%d), mem(%p)\n" , This, This->glDescription.level, This->glDescription.glFormat, This->glDescription.glType, This->resource.allocatedMemory);
375 if (This->resource.format == WINED3DFMT_DXT1 ||
376 This->resource.format == WINED3DFMT_DXT2 ||
377 This->resource.format == WINED3DFMT_DXT3 ||
378 This->resource.format == WINED3DFMT_DXT4 ||
379 This->resource.format == WINED3DFMT_DXT5) {
380 TRACE("Locking a compressed texture\n");
381 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) { /* we can assume this as the texture would not have been created otherwise */
382 GL_EXTCALL(glGetCompressedTexImageARB)(This->glDescription.target,
383 This->glDescription.level,
384 This->resource.allocatedMemory);
386 } else {
387 FIXME("(%p) attempting to lock a compressed texture when texture compression isn't supported by opengl\n", This);
389 } else {
390 glGetTexImage(This->glDescription.target,
391 This->glDescription.level,
392 This->glDescription.glFormat,
393 This->glDescription.glType,
394 This->resource.allocatedMemory);
395 vcheckGLcall("glGetTexImage");
396 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
397 /* some games (e.g. warhammer 40k) don't work with the odd pitchs properly, preventing
398 the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
399 repack the texture so that the bpp * width pitch can be used instead of the bpp * pow2width.
401 Were doing this...
403 instead of boxing the texture :
404 |<-texture width ->| -->pow2width| /\
405 |111111111111111111| | |
406 |222 Texture 222222| boxed empty | texture height
407 |3333 Data 33333333| | |
408 |444444444444444444| | \/
409 ----------------------------------- |
410 | boxed empty | boxed empty | pow2height
411 | | | \/
412 -----------------------------------
415 were repacking the data to the expected texture width
417 |<-texture width ->| -->pow2width| /\
418 |111111111111111111222222222222222| |
419 |222333333333333333333444444444444| texture height
420 |444444 | |
421 | | \/
422 | | |
423 | empty | pow2height
424 | | \/
425 -----------------------------------
427 == is the same as
429 |<-texture width ->| /\
430 |111111111111111111|
431 |222222222222222222|texture height
432 |333333333333333333|
433 |444444444444444444| \/
434 --------------------
436 this also means that any references to allocatedMemory should work with the data as if were a standard texture with a non-power2 width instead of texture boxed up to be a power2 texture.
438 internally the texture is still stored in a boxed format so any references to textureName will get a boxed texture with width pow2width and not a texture of width currentDesc.Width.
440 if (This->nonpow2) {
441 BYTE* dataa, *datab;
442 int pitcha = 0, pitchb = 0;
443 int y;
444 pitcha = This->bytesPerPixel * This->currentDesc.Width;
445 pitchb = This->bytesPerPixel * This->pow2Width;
446 datab = dataa = This->resource.allocatedMemory;
447 FIXME("(%p) : Repacking the surface data from pitch %d to pitch %d\n", This, pitcha, pitchb);
448 for (y = 1 ; y < This->currentDesc.Height; y++) {
449 dataa += pitcha; /* skip the first row */
450 datab += pitchb;
451 memcpy(dataa, datab, pitcha);
456 LEAVE_GL();
458 } else { /* Nothing to do */
459 TRACE("Memory %p already allocted for texture\n", This->resource.allocatedMemory);
462 if (NULL == pRect) {
463 pLockedRect->pBits = This->resource.allocatedMemory;
464 } else{
465 if (This->resource.format == D3DFMT_DXT1) { /* DXT1 is half byte per pixel */
466 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
467 } else {
468 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
472 } else if (D3DUSAGE_RENDERTARGET & This->resource.usage && !(Flags&D3DLOCK_DISCARD)) { /* render surfaces */
474 GLint prev_store;
475 GLint prev_read;
476 BOOL notInContext = FALSE;
477 IWineD3DSwapChainImpl *targetSwapChain = NULL;
480 ENTER_GL();
483 * for render->surface copy begin to begin of allocatedMemory
484 * unlock can be more easy
487 TRACE("locking a render target\n");
489 if (This->resource.allocatedMemory == NULL)
490 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 ,This->resource.size);
492 This->activeLock = TRUE; /*When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory*/
493 pLockedRect->pBits = This->resource.allocatedMemory;
495 glFlush();
496 vcheckGLcall("glFlush");
497 glGetIntegerv(GL_READ_BUFFER, &prev_read);
498 vcheckGLcall("glIntegerv");
499 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
500 vcheckGLcall("glIntegerv");
502 /* Here's what we have to do:
503 See if the swapchain has the same context as the renderTarget or the surface is the render target.
504 Otherwise, see if were sharing a context with the implicit swapchain (because we're using a shared context model!)
505 and use the front back buffer as required.
506 if not, we need to switch contexts and then switchback at the end.
508 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
509 IWineD3DSurface_GetContainer(myDevice->renderTarget, &IID_IWineD3DSwapChain, (void **)&targetSwapChain);
511 /* NOTE: In a shared context environment the renderTarget will use the same context as the implicit swapchain (we're not in a shared environment yet! */
512 if ((swapchain == targetSwapChain && targetSwapChain != NULL) || iface == myDevice->renderTarget) {
513 if (iface == myDevice->renderTarget || iface == swapchain->backBuffer) {
514 TRACE("locking back buffer\n");
515 glReadBuffer(GL_BACK);
516 } else if (iface == swapchain->frontBuffer) {
517 TRACE("locking front\n");
518 glReadBuffer(GL_FRONT);
519 } else if (iface == myDevice->depthStencilBuffer) {
520 FIXME("Stencil Buffer lock unsupported for now\n");
521 } else {
522 FIXME("(%p) Shouldn't have got here!\n", This);
523 glReadBuffer(GL_BACK);
525 } else if (swapchain != NULL) {
526 IWineD3DSwapChainImpl *implSwapChain;
527 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
528 if (swapchain->glCtx == implSwapChain->render_ctx && swapchain->drawable == implSwapChain->win) {
529 /* This will fail for the implicit swapchain, which is why there needs to be a context manager */
530 if (iface == swapchain->backBuffer) {
531 glReadBuffer(GL_BACK);
532 } else if (iface == swapchain->frontBuffer) {
533 glReadBuffer(GL_FRONT);
534 } else if (iface == myDevice->depthStencilBuffer) {
535 FIXME("Stencil Buffer lock unsupported for now\n");
536 } else {
537 FIXME("Should have got here!\n");
538 glReadBuffer(GL_BACK);
540 } else {
541 /* We need to switch contexts to be able to read the buffer!!! */
542 FIXME("The buffer requested isn't in the current openGL context\n");
543 notInContext = TRUE;
544 /* TODO: check the contexts, to see if were shared with the current context */
546 IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
548 if (swapchain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
549 if (targetSwapChain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)targetSwapChain);
552 /** the depth stencil in openGL has a format of GL_FLOAT
553 * which should be good for WINED3DFMT_D16_LOCKABLE
554 * and WINED3DFMT_D16
555 * it is unclear what format the stencil buffer is in except.
556 * 'Each index is converted to fixed point...
557 * If GL_MAP_STENCIL is GL_TRUE, indices are replaced by their
558 * mappings in the table GL_PIXEL_MAP_S_TO_S.
559 * glReadPixels(This->lockedRect.left,
560 * This->lockedRect.bottom - j - 1,
561 * This->lockedRect.right - This->lockedRect.left,
562 * 1,
563 * GL_DEPTH_COMPONENT,
564 * type,
565 * (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
566 *****************************************/
567 if (!notInContext) { /* Only read the buffer if it's in the current context */
568 long j;
569 #if 0
570 /* Bizarly it takes 120 millseconds to get an 800x600 region a line at a time, but only 10 to get the whole lot every time,
571 * This is on an ATI9600, and may be format dependent, anyhow this hack makes this demo dx9_2d_demo_game
572 * run ten times faster!
573 * ************************************/
574 BOOL ati_performance_hack = FALSE;
575 ati_performance_hack = (This->lockedRect.bottom - This->lockedRect.top > 10) || (This->lockedRect.right - This->lockedRect.left > 10)? TRUE: FALSE;
576 #endif
577 if ((This->lockedRect.left == 0 && This->lockedRect.top == 0 &&
578 This->lockedRect.right == This->currentDesc.Width
579 && This->lockedRect.bottom == This->currentDesc.Height)) {
580 glReadPixels(0, 0,
581 This->currentDesc.Width,
582 This->currentDesc.Height,
583 This->glDescription.glFormat,
584 This->glDescription.glType,
585 (char *)pLockedRect->pBits);
586 } else if (This->lockedRect.left == 0 && This->lockedRect.right == This->currentDesc.Width) {
587 glReadPixels(0,
588 This->lockedRect.top,
589 This->currentDesc.Width,
590 This->currentDesc.Height,
591 This->glDescription.glFormat,
592 This->glDescription.glType,
593 (char *)pLockedRect->pBits);
594 } else{
596 for (j = This->lockedRect.top; j < This->lockedRect.bottom - This->lockedRect.top; ++j) {
597 glReadPixels(This->lockedRect.left,
598 This->lockedRect.bottom - j - 1,
599 This->lockedRect.right - This->lockedRect.left,
601 This->glDescription.glFormat,
602 This->glDescription.glType,
603 (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
607 vcheckGLcall("glReadPixels");
608 TRACE("Resetting buffer\n");
609 glReadBuffer(prev_read);
610 vcheckGLcall("glReadBuffer");
612 LEAVE_GL();
614 } else if (D3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
616 if (!messages & 1) {
617 FIXME("TODO stencil depth surface locking surf%p usage(%lu)\n", This, This->resource.usage);
620 glReadPixels(This->lockedRect.left,
621 This->lockedRect.bottom - j - 1,
622 This->lockedRect.right - This->lockedRect.left,
624 GL_STENCIL_INDEX or GL_DEPTH_COMPONENT
628 messages |= 1;
630 } else {
631 FIXME("unsupported locking to surface surf@%p usage(%lu)\n", This, This->resource.usage);
634 if (Flags & (D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_READONLY)) {
635 /* Don't dirtify */
636 } else {
637 IWineD3DBaseTexture *pBaseTexture;
639 * Dirtify on lock
640 * as seen in msdn docs
642 IWineD3DSurface_AddDirtyRect(iface, &This->lockedRect);
644 /** Dirtify Container if needed */
645 if (D3D_OK == IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&pBaseTexture) && pBaseTexture != NULL) {
646 TRACE("Making container dirty\n");
647 IWineD3DBaseTexture_SetDirty(pBaseTexture, TRUE);
648 IWineD3DBaseTexture_Release(pBaseTexture);
649 } else {
650 TRACE("Surface is standalone, no need to dirty the container\n");
654 TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect->pBits, pLockedRect->Pitch, This->Dirty);
656 This->locked = TRUE;
657 return D3D_OK;
660 HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
661 GLint skipBytes = 0;
662 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
663 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
664 const char *buffername = "";
665 IWineD3DSwapChainImpl *swapchain = NULL;
667 if (FALSE == This->locked) {
668 WARN("trying to Unlock an unlocked surf@%p\n", This);
669 return D3DERR_INVALIDCALL;
672 if (D3DUSAGE_RENDERTARGET & This->resource.usage) {
673 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
675 if ((swapchain != NULL) && iface == swapchain->backBuffer) {
676 buffername = "backBuffer";
677 } else if ((swapchain != NULL) && iface == swapchain->frontBuffer) {
678 buffername = "frontBuffer";
679 } else if (iface == myDevice->depthStencilBuffer) {
680 buffername = "depthStencilBuffer";
681 } else if (iface == myDevice->renderTarget) {
682 buffername = "renderTarget";
686 if (swapchain != NULL) {
687 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
690 TRACE("(%p %s) : dirtyfied(%d)\n", This, buffername, This->Dirty);
692 if (FALSE == This->Dirty) {
693 TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
694 goto unlock_end;
697 if (0 == This->resource.usage) { /* classic surface */
699 * nothing to do
700 * waiting to reload the surface via IDirect3DDevice8::UpdateTexture
702 } else if (D3DUSAGE_RENDERTARGET & This->resource.usage) { /* render surfaces */
704 /****************************
705 * TODO: Render targets are 'special' and
706 * ?some? locking needs to be passed onto the context manager
707 * so that it becomes possible to use auxiliary buffers, pbuffers
708 * render-to-texture, shared, cached contexts etc...
709 * ****************************/
710 IWineD3DSwapChainImpl *implSwapChain;
711 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
713 if (iface == implSwapChain->backBuffer || iface == implSwapChain->frontBuffer || iface == myDevice->renderTarget) {
714 GLint prev_store;
715 GLint prev_draw;
716 GLint prev_rasterpos[4];
718 ENTER_GL();
720 glFlush();
721 vcheckGLcall("glFlush");
722 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
723 vcheckGLcall("glIntegerv");
724 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
725 vcheckGLcall("glIntegerv");
726 glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
727 vcheckGLcall("glIntegerv");
728 glPixelZoom(1.0, -1.0);
729 vcheckGLcall("glPixelZoom");
731 /* glDrawPixels transforms the raster position as though it was a vertex -
732 we want to draw at screen position 0,0 - Set up ortho (rhw) mode as
733 per drawprim (and leave set - it will sort itself out due to last_was_rhw */
734 if ( (!myDevice->last_was_rhw) || (myDevice->viewport_changed) ) {
736 double X, Y, height, width, minZ, maxZ;
737 myDevice->last_was_rhw = TRUE;
738 myDevice->viewport_changed = FALSE;
740 /* Transformed already into viewport coordinates, so we do not need transform
741 matrices. Reset all matrices to identity and leave the default matrix in world
742 mode. */
743 glMatrixMode(GL_MODELVIEW);
744 checkGLcall("glMatrixMode");
745 glLoadIdentity();
746 checkGLcall("glLoadIdentity");
748 glMatrixMode(GL_PROJECTION);
749 checkGLcall("glMatrixMode");
750 glLoadIdentity();
751 checkGLcall("glLoadIdentity");
753 /* Set up the viewport to be full viewport */
754 X = myDevice->stateBlock->viewport.X;
755 Y = myDevice->stateBlock->viewport.Y;
756 height = myDevice->stateBlock->viewport.Height;
757 width = myDevice->stateBlock->viewport.Width;
758 minZ = myDevice->stateBlock->viewport.MinZ;
759 maxZ = myDevice->stateBlock->viewport.MaxZ;
760 TRACE("Calling glOrtho with %f, %f, %f, %f\n", width, height, -minZ, -maxZ);
761 glOrtho(X, X + width, Y + height, Y, -minZ, -maxZ);
762 checkGLcall("glOrtho");
764 /* Window Coord 0 is the middle of the first pixel, so translate by half
765 a pixel (See comment above glTranslate below) */
766 glTranslatef(0.5, 0.5, 0);
767 checkGLcall("glTranslatef(0.5, 0.5, 0)");
770 if (iface == implSwapChain->backBuffer || iface == myDevice->renderTarget) {
771 glDrawBuffer(GL_BACK);
772 } else if (iface == implSwapChain->frontBuffer) {
773 glDrawBuffer(GL_FRONT);
776 vcheckGLcall("glDrawBuffer");
778 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
779 glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
780 glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width);
782 /* And back buffers are not blended */
783 glDisable(GL_BLEND);
785 glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
786 vcheckGLcall("glRasterPos2f");
787 switch (This->resource.format) {
788 case WINED3DFMT_X4R4G4B4:
790 int size;
791 unsigned short *data;
792 data = (unsigned short *)This->resource.allocatedMemory;
793 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
794 while(size > 0) {
795 *data |= 0xF000;
796 data++;
797 size--;
800 case WINED3DFMT_A4R4G4B4:
802 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
803 GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4_REV, This->resource.allocatedMemory);
804 vcheckGLcall("glDrawPixels");
806 break;
807 case WINED3DFMT_R5G6B5:
809 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
810 GL_RGB, GL_UNSIGNED_SHORT_5_6_5, This->resource.allocatedMemory);
811 vcheckGLcall("glDrawPixels");
813 break;
814 case WINED3DFMT_X1R5G5B5:
816 int size;
817 unsigned short *data;
818 data = (unsigned short *)This->resource.allocatedMemory;
819 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
820 while(size > 0) {
821 *data |= 0x8000;
822 data++;
823 size--;
826 case WINED3DFMT_A1R5G5B5:
828 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
829 GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, This->resource.allocatedMemory);
830 vcheckGLcall("glDrawPixels");
832 break;
833 case WINED3DFMT_R8G8B8:
835 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
836 GL_RGB, GL_UNSIGNED_BYTE, This->resource.allocatedMemory);
837 vcheckGLcall("glDrawPixels");
839 break;
840 case WINED3DFMT_X8R8G8B8: /* make sure the X byte is set to alpha on, since it
841 could be any random value this fixes the intro move in Pirates! */
843 int size;
844 unsigned int *data;
845 data = (unsigned int *)This->resource.allocatedMemory;
846 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
847 while(size > 0) {
848 *data |= 0xFF000000;
849 data++;
850 size--;
853 case WINED3DFMT_A8R8G8B8:
855 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
856 vcheckGLcall("glPixelStorei");
857 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
858 GL_BGRA, GL_UNSIGNED_BYTE, This->resource.allocatedMemory);
859 vcheckGLcall("glDrawPixels");
860 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
861 vcheckGLcall("glPixelStorei");
863 break;
864 case WINED3DFMT_A2R10G10B10:
866 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
867 vcheckGLcall("glPixelStorei");
868 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
869 GL_BGRA, GL_UNSIGNED_INT_2_10_10_10_REV, This->resource.allocatedMemory);
870 vcheckGLcall("glDrawPixels");
871 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
872 vcheckGLcall("glPixelStorei");
874 break;
875 default:
876 FIXME("Unsupported Format %u in locking func\n", This->resource.format);
879 glPixelZoom(1.0,1.0);
880 vcheckGLcall("glPixelZoom");
881 glDrawBuffer(prev_draw);
882 vcheckGLcall("glDrawBuffer");
883 glRasterPos3iv(&prev_rasterpos[0]);
884 vcheckGLcall("glRasterPos3iv");
886 /* Reset to previous pack row length / blending state */
887 glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
888 if (myDevice->stateBlock->renderState[D3DRS_ALPHABLENDENABLE]) glEnable(GL_BLEND);
890 LEAVE_GL();
892 /** restore clean dirty state */
893 IWineD3DSurface_CleanDirtyRect(iface);
895 } else {
896 FIXME("unsupported unlocking to Rendering surface surf@%p usage(%lu)\n", This, This->resource.usage);
898 IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
900 } else if (D3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
902 if (iface == myDevice->depthStencilBuffer) {
903 FIXME("TODO stencil depth surface unlocking surf@%p usage(%lu)\n", This, This->resource.usage);
904 } else {
905 FIXME("unsupported unlocking to StencilDepth surface surf@%p usage(%lu)\n", This, This->resource.usage);
908 } else {
909 FIXME("unsupported unlocking to surface surf@%p usage(%lu)\n", This, This->resource.usage);
912 unlock_end:
913 This->locked = FALSE;
914 memset(&This->lockedRect, 0, sizeof(RECT));
915 return D3D_OK;
918 HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
919 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
920 FIXME("No support for GetDC yet for surface %p\n", This);
921 return D3DERR_INVALIDCALL;
924 HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
925 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
926 FIXME("No support for ReleaseDC yet for surface %p\n", This);
927 return D3DERR_INVALIDCALL;
930 /* ******************************************************
931 IWineD3DSurface Internal (No mapping to directx api) parts follow
932 ****************************************************** */
933 HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface) {
934 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
936 if (This->inTexture) {
937 TRACE("Surface already in texture\n");
938 return D3D_OK;
940 if (This->Dirty == FALSE) {
941 TRACE("surface isn't dirty\n");
942 return D3D_OK;
945 This->Dirty = FALSE;
947 /* Resources are placed in system RAM and do not need to be recreated when a device is lost.
948 * These resources are not bound by device size or format restrictions. Because of this,
949 * these resources cannot be accessed by the Direct3D device nor set as textures or render targets.
950 * However, these resources can always be created, locked, and copied.
951 * In general never store scratch or system mem textures in the video ram. However it is allowed
952 * for system memory textures when WINED3DDEVCAPS_TEXTURESYSTEMMEMORY is set but it isn't right now.
954 if (This->resource.pool == D3DPOOL_SCRATCH || This->resource.pool == D3DPOOL_SYSTEMMEM)
956 FIXME("(%p) Operation not supported for scratch or SYSTEMMEM textures\n",This);
957 return D3DERR_INVALIDCALL;
960 if (This->inPBuffer) {
961 ENTER_GL();
963 if (This->glDescription.level != 0)
964 FIXME("Surface in texture is only supported for level 0\n");
965 else if (This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8 ||
966 This->resource.format == WINED3DFMT_DXT1 || This->resource.format == WINED3DFMT_DXT2 ||
967 This->resource.format == WINED3DFMT_DXT3 || This->resource.format == WINED3DFMT_DXT4 ||
968 This->resource.format == WINED3DFMT_DXT5)
969 FIXME("Format %d not supported\n", This->resource.format);
970 else {
971 GLint prevRead;
972 glGetIntegerv(GL_READ_BUFFER, &prevRead);
973 vcheckGLcall("glGetIntegerv");
974 glReadBuffer(GL_BACK);
975 vcheckGLcall("glReadBuffer");
977 glCopyTexImage2D(This->glDescription.target,
978 This->glDescription.level,
979 This->glDescription.glFormatInternal,
982 This->currentDesc.Width,
983 This->currentDesc.Height,
986 checkGLcall("glCopyTexImage2D");
987 glReadBuffer(prevRead);
988 vcheckGLcall("glReadBuffer");
989 TRACE("Updating target %d\n", This->glDescription.target);
990 This->inTexture = TRUE;
992 LEAVE_GL();
993 return D3D_OK;
996 if ((This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8) &&
997 !GL_SUPPORT(EXT_PALETTED_TEXTURE)) {
999 * wanted a paletted texture and not really support it in HW
1000 * so software emulation code begin
1002 UINT i;
1003 PALETTEENTRY* pal = This->resource.wineD3DDevice->palettes[This->resource.wineD3DDevice->currentPalette];
1004 VOID* surface = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->currentDesc.Width * This->currentDesc.Height * sizeof(DWORD));
1005 BYTE* dst = (BYTE*) surface;
1006 BYTE* src = (BYTE*) This->resource.allocatedMemory;
1008 for (i = 0; i < This->currentDesc.Width * This->currentDesc.Height; i++) {
1009 BYTE color = *src++;
1010 *dst++ = pal[color].peRed;
1011 *dst++ = pal[color].peGreen;
1012 *dst++ = pal[color].peBlue;
1013 if (This->resource.format == WINED3DFMT_A8P8)
1014 *dst++ = pal[color].peFlags;
1015 else
1016 *dst++ = 0xFF;
1019 ENTER_GL();
1021 TRACE("Calling glTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
1022 This->glDescription.target,
1023 This->glDescription.level,
1024 GL_RGBA,
1025 This->currentDesc.Width,
1026 This->currentDesc.Height,
1028 GL_RGBA,
1029 GL_UNSIGNED_BYTE,
1030 surface);
1031 glTexImage2D(This->glDescription.target,
1032 This->glDescription.level,
1033 GL_RGBA,
1034 This->currentDesc.Width,
1035 This->currentDesc.Height,
1037 GL_RGBA,
1038 GL_UNSIGNED_BYTE,
1039 surface);
1040 checkGLcall("glTexImage2D");
1041 HeapFree(GetProcessHeap(), 0, surface);
1043 LEAVE_GL();
1045 return D3D_OK;
1048 /* TODO: Compressed non-power 2 support */
1050 if (This->resource.format == WINED3DFMT_DXT1 ||
1051 This->resource.format == WINED3DFMT_DXT2 ||
1052 This->resource.format == WINED3DFMT_DXT3 ||
1053 This->resource.format == WINED3DFMT_DXT4 ||
1054 This->resource.format == WINED3DFMT_DXT5) {
1055 if (!GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
1056 FIXME("Using DXT1/3/5 without advertized support\n");
1057 } else if (This->resource.allocatedMemory) {
1058 TRACE("Calling glCompressedTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, sz=%d, Mem=%p\n",
1059 This->glDescription.target,
1060 This->glDescription.level,
1061 This->glDescription.glFormatInternal,
1062 This->currentDesc.Width,
1063 This->currentDesc.Height,
1065 This->resource.size,
1066 This->resource.allocatedMemory);
1068 ENTER_GL();
1070 GL_EXTCALL(glCompressedTexImage2DARB)(This->glDescription.target,
1071 This->glDescription.level,
1072 This->glDescription.glFormatInternal,
1073 This->currentDesc.Width,
1074 This->currentDesc.Height,
1076 This->resource.size,
1077 This->resource.allocatedMemory);
1078 checkGLcall("glCommpressedTexImage2D");
1080 LEAVE_GL();
1082 if(This->activeLock == FALSE){
1083 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1084 This->resource.allocatedMemory = NULL;
1087 } else {
1089 /* TODO: possibly use texture rectangle (though we are probably more compatible without it) */
1090 if (NP2_REPACK == wined3d_settings.nonpower2_mode && This->nonpow2 == TRUE) {
1093 TRACE("non power of two support\n");
1094 ENTER_GL();
1095 TRACE("(%p) Calling 2 glTexImage2D %x i=%d, d3dfmt=%s, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n", This,
1096 This->glDescription.target,
1097 This->glDescription.level,
1098 debug_d3dformat(This->resource.format),
1099 This->glDescription.glFormatInternal,
1100 This->pow2Width,
1101 This->pow2Height,
1103 This->glDescription.glFormat,
1104 This->glDescription.glType,
1105 NULL);
1107 glTexImage2D(This->glDescription.target,
1108 This->glDescription.level,
1109 This->glDescription.glFormatInternal,
1110 This->pow2Width,
1111 This->pow2Height,
1112 0/*border*/,
1113 This->glDescription.glFormat,
1114 This->glDescription.glType,
1115 NULL);
1117 checkGLcall("glTexImage2D");
1118 if (This->resource.allocatedMemory != NULL) {
1119 TRACE("(%p) Calling glTexSubImage2D w(%d) h(%d) mem(%p)\n", This, This->currentDesc.Width, This->currentDesc.Height, This->resource.allocatedMemory);
1120 /* And map the non-power two data into the top left corner */
1121 glTexSubImage2D(
1122 This->glDescription.target,
1123 This->glDescription.level,
1124 0 /* xoffset */,
1125 0 /* ysoffset */ ,
1126 This->currentDesc.Width,
1127 This->currentDesc.Height,
1128 This->glDescription.glFormat,
1129 This->glDescription.glType,
1130 This->resource.allocatedMemory
1132 checkGLcall("glTexSubImage2D");
1134 LEAVE_GL();
1136 } else {
1138 TRACE("Calling 2 glTexImage2D %x i=%d, d3dfmt=%s, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
1139 This->glDescription.target,
1140 This->glDescription.level,
1141 debug_d3dformat(This->resource.format),
1142 This->glDescription.glFormatInternal,
1143 This->pow2Width,
1144 This->pow2Height,
1146 This->glDescription.glFormat,
1147 This->glDescription.glType,
1148 This->resource.allocatedMemory);
1150 ENTER_GL();
1151 glTexImage2D(This->glDescription.target,
1152 This->glDescription.level,
1153 This->glDescription.glFormatInternal,
1154 This->pow2Width,
1155 This->pow2Height,
1156 0 /* border */,
1157 This->glDescription.glFormat,
1158 This->glDescription.glType,
1159 This->resource.allocatedMemory);
1160 checkGLcall("glTexImage2D");
1161 LEAVE_GL();
1164 #if 0
1166 static unsigned int gen = 0;
1167 char buffer[4096];
1168 ++gen;
1169 if ((gen % 10) == 0) {
1170 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
1171 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
1174 * debugging crash code
1175 if (gen == 250) {
1176 void** test = NULL;
1177 *test = 0;
1181 #endif
1182 if(This->activeLock == FALSE){
1183 HeapFree(GetProcessHeap(),0,This->resource.allocatedMemory);
1184 This->resource.allocatedMemory = NULL;
1189 return D3D_OK;
1192 #include <errno.h>
1193 #include <stdio.h>
1194 HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename) {
1195 FILE* f = NULL;
1196 UINT i, y;
1197 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1198 char *allocatedMemory;
1199 char *textureRow;
1200 IWineD3DSwapChain *swapChain = NULL;
1201 int width, height;
1202 GLuint tmpTexture;
1203 DWORD color;
1204 /*FIXME:
1205 Textures my not be stored in ->allocatedgMemory and a GlTexture
1206 so we should lock the surface before saving a snapshot, or at least check that
1208 /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
1209 by calling GetTexImage and in compressed form by calling
1210 GetCompressedTexImageARB. Queried compressed images can be saved and
1211 later reused by calling CompressedTexImage[123]DARB. Pre-compressed
1212 texture images do not need to be processed by the GL and should
1213 significantly improve texture loading performance relative to uncompressed
1214 images. */
1216 /* Setup the width and height to be the internal texture width and height. */
1217 width = This->pow2Width;
1218 height = This->pow2Height;
1219 /* check to see if were a 'virtual' texture e.g. were not a pbuffer of texture were a back buffer*/
1220 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapChain);
1222 if (swapChain || This->inPBuffer) { /* if were not a real texture then read the back buffer into a real texture*/
1223 /* we don't want to interfere with the back buffer so read the data into a temporary texture and then save the data out of the temporary texture */
1224 GLint prevRead;
1225 ENTER_GL();
1226 FIXME("(%p) This surface needs to be locked before a snapshot can be taken\n", This);
1227 glEnable(GL_TEXTURE_2D);
1229 glGenTextures(1, &tmpTexture);
1230 glBindTexture(GL_TEXTURE_2D, tmpTexture);
1232 glTexImage2D(GL_TEXTURE_2D,
1234 GL_RGBA,
1235 width,
1236 height,
1237 0/*border*/,
1238 GL_RGBA,
1239 GL_UNSIGNED_INT_8_8_8_8_REV,
1240 NULL);
1242 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1243 vcheckGLcall("glGetIntegerv");
1244 glReadBuffer(GL_BACK);
1245 vcheckGLcall("glReadBuffer");
1246 glCopyTexImage2D(GL_TEXTURE_2D,
1248 GL_RGBA,
1251 width,
1252 height,
1255 checkGLcall("glCopyTexImage2D");
1256 glReadBuffer(prevRead);
1257 LEAVE_GL();
1259 } else { /* bind the real texture */
1260 IWineD3DSurface_PreLoad(iface);
1262 allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width * height * 4);
1263 ENTER_GL();
1264 FIXME("Saving texture level %d width %d height %d\n", This->glDescription.level, width, height);
1265 glGetTexImage(GL_TEXTURE_2D,
1266 This->glDescription.level,
1267 GL_RGBA,
1268 GL_UNSIGNED_INT_8_8_8_8_REV,
1269 allocatedMemory);
1270 checkGLcall("glTexImage2D");
1271 if (tmpTexture) {
1272 glBindTexture(GL_TEXTURE_2D, 0);
1273 glDeleteTextures(1, &tmpTexture);
1275 LEAVE_GL();
1277 f = fopen(filename, "w+");
1278 if (NULL == f) {
1279 ERR("opening of %s failed with: %s\n", filename, strerror(errno));
1280 return D3DERR_INVALIDCALL;
1282 /* Save the dat out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha chanel*/
1283 TRACE("(%p) opened %s with format %s\n", This, filename, debug_d3dformat(This->resource.format));
1284 /* TGA header */
1285 fputc(0,f);
1286 fputc(0,f);
1287 fputc(2,f);
1288 fputc(0,f);
1289 fputc(0,f);
1290 fputc(0,f);
1291 fputc(0,f);
1292 fputc(0,f);
1293 fputc(0,f);
1294 fputc(0,f);
1295 fputc(0,f);
1296 fputc(0,f);
1297 /* short width*/
1298 fwrite(&width,2,1,f);
1299 /* short height */
1300 fwrite(&height,2,1,f);
1301 /* format rgba */
1302 fputc(0x20,f);
1303 fputc(0x28,f);
1304 /* raw data */
1305 /* if the data is upside down if we've fetched it from a back buffer, so it needs flipping again to make it the correct way up*/
1306 if(swapChain)
1307 textureRow = allocatedMemory + (width * (height - 1) *4);
1308 else
1309 textureRow = allocatedMemory;
1310 for (y = 0 ; y < height; y++) {
1311 for (i = 0; i < width; i++) {
1312 color = *((DWORD*)textureRow);
1313 fputc((color >> 16) & 0xFF, f); /* B */
1314 fputc((color >> 8) & 0xFF, f); /* G */
1315 fputc((color >> 0) & 0xFF, f); /* R */
1316 fputc((color >> 24) & 0xFF, f); /* A */
1317 textureRow += 4;
1319 /* take two rows of the pointer to the texture memory */
1320 if(swapChain)
1321 (textureRow-= width << 3);
1324 TRACE("Closing file\n");
1325 fclose(f);
1327 if(swapChain) {
1328 IWineD3DSwapChain_Release(swapChain);
1330 HeapFree(GetProcessHeap(), 0, allocatedMemory);
1331 return D3D_OK;
1334 HRESULT WINAPI IWineD3DSurfaceImpl_CleanDirtyRect(IWineD3DSurface *iface) {
1335 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1336 This->Dirty = FALSE;
1337 This->dirtyRect.left = This->currentDesc.Width;
1338 This->dirtyRect.top = This->currentDesc.Height;
1339 This->dirtyRect.right = 0;
1340 This->dirtyRect.bottom = 0;
1341 TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Dirty, This->dirtyRect.left,
1342 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
1343 return D3D_OK;
1347 * Slightly inefficient way to handle multiple dirty rects but it works :)
1349 extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) {
1350 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1351 IWineD3DBaseTexture *baseTexture = NULL;
1352 This->Dirty = TRUE;
1353 if (NULL != pDirtyRect) {
1354 This->dirtyRect.left = min(This->dirtyRect.left, pDirtyRect->left);
1355 This->dirtyRect.top = min(This->dirtyRect.top, pDirtyRect->top);
1356 This->dirtyRect.right = max(This->dirtyRect.right, pDirtyRect->right);
1357 This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
1358 } else {
1359 This->dirtyRect.left = 0;
1360 This->dirtyRect.top = 0;
1361 This->dirtyRect.right = This->currentDesc.Width;
1362 This->dirtyRect.bottom = This->currentDesc.Height;
1364 TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Dirty, This->dirtyRect.left,
1365 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
1366 /* if the container is a basetexture then mark it dirty. */
1367 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == D3D_OK) {
1368 TRACE("Passing to conatiner\n");
1369 IWineD3DBaseTexture_SetDirty(baseTexture, TRUE);
1370 IWineD3DBaseTexture_Release(baseTexture);
1372 return D3D_OK;
1375 HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
1376 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1378 TRACE("This %p, container %p\n", This, container);
1380 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
1382 TRACE("Setting container to %p from %p\n", container, This->container);
1383 This->container = container;
1385 return D3D_OK;
1388 HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
1389 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1391 if (This->resource.format != WINED3DFMT_UNKNOWN) {
1392 FIXME("(%p) : The foramt of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
1393 return D3DERR_INVALIDCALL;
1396 TRACE("(%p) : Setting texture foramt to (%d,%s)\n", This, format, debug_d3dformat(format));
1397 if (format == WINED3DFMT_UNKNOWN) {
1398 This->resource.size = 0;
1399 } else if (format == WINED3DFMT_DXT1) {
1400 /* DXT1 is half byte per pixel */
1401 This->resource.size = ((max(This->pow2Width, 4) * D3DFmtGetBpp(This->resource.wineD3DDevice, format)) * max(This->pow2Height, 4)) >> 1;
1403 } else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
1404 format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) {
1405 This->resource.size = ((max(This->pow2Width, 4) * D3DFmtGetBpp(This->resource.wineD3DDevice, format)) * max(This->pow2Height, 4));
1406 } else {
1407 This->resource.size = (This->pow2Width * D3DFmtGetBpp(This->resource.wineD3DDevice, format)) * This->pow2Height;
1411 /* Setup some glformat defaults */
1412 if (format != WINED3DFMT_UNKNOWN) {
1413 This->glDescription.glFormat = D3DFmt2GLFmt(This->resource.wineD3DDevice, format);
1414 This->glDescription.glFormatInternal = D3DFmt2GLIntFmt(This->resource.wineD3DDevice, format);
1415 This->glDescription.glType = D3DFmt2GLType(This->resource.wineD3DDevice, format);
1416 } else {
1417 This->glDescription.glFormat = 0;
1418 This->glDescription.glFormatInternal = 0;
1419 This->glDescription.glType = 0;
1422 if (format != WINED3DFMT_UNKNOWN) {
1423 This->bytesPerPixel = D3DFmtGetBpp(This->resource.wineD3DDevice, format);
1424 This->pow2Size = (This->pow2Width * This->bytesPerPixel) * This->pow2Height;
1425 } else {
1426 This->bytesPerPixel = 0;
1427 This->pow2Size = 0;
1430 This->lockable = (WINED3DFMT_D16_LOCKABLE == format) ? TRUE : This->lockable;
1432 This->resource.format = format;
1434 TRACE("(%p) : Size %d, pow2Size %d, bytesPerPixel %d, glFormat %d, glFotmatInternal %d, glType %d\n", This, This->resource.size, This->pow2Size, This->bytesPerPixel, This->glDescription.glFormat, This->glDescription.glFormatInternal, This->glDescription.glType);
1436 return D3D_OK;
1439 /* TODO: replace this function with context management routines */
1440 HRESULT WINAPI IWineD3DSurfaceImpl_SetPBufferState(IWineD3DSurface *iface, BOOL inPBuffer, BOOL inTexture) {
1441 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1443 This->inPBuffer = inPBuffer;
1444 This->inTexture = inTexture;
1445 return D3D_OK;
1448 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
1450 /* IUnknown */
1451 IWineD3DSurfaceImpl_QueryInterface,
1452 IWineD3DSurfaceImpl_AddRef,
1453 IWineD3DSurfaceImpl_Release,
1454 /* IWineD3DResource */
1455 IWineD3DSurfaceImpl_GetParent,
1456 IWineD3DSurfaceImpl_GetDevice,
1457 IWineD3DSurfaceImpl_SetPrivateData,
1458 IWineD3DSurfaceImpl_GetPrivateData,
1459 IWineD3DSurfaceImpl_FreePrivateData,
1460 IWineD3DSurfaceImpl_SetPriority,
1461 IWineD3DSurfaceImpl_GetPriority,
1462 IWineD3DSurfaceImpl_PreLoad,
1463 IWineD3DSurfaceImpl_GetType,
1464 /* IWineD3DSurface */
1465 IWineD3DSurfaceImpl_GetContainerParent,
1466 IWineD3DSurfaceImpl_GetContainer,
1467 IWineD3DSurfaceImpl_GetDesc,
1468 IWineD3DSurfaceImpl_LockRect,
1469 IWineD3DSurfaceImpl_UnlockRect,
1470 IWineD3DSurfaceImpl_GetDC,
1471 IWineD3DSurfaceImpl_ReleaseDC,
1472 /* Internal use: */
1473 IWineD3DSurfaceImpl_CleanDirtyRect,
1474 IWineD3DSurfaceImpl_AddDirtyRect,
1475 IWineD3DSurfaceImpl_LoadTexture,
1476 IWineD3DSurfaceImpl_SaveSnapshot,
1477 IWineD3DSurfaceImpl_SetContainer,
1478 IWineD3DSurfaceImpl_SetPBufferState,
1479 IWineD3DSurfaceImpl_SetGlTextureDesc,
1480 IWineD3DSurfaceImpl_GetGlDesc,
1481 IWineD3DSurfaceImpl_GetData,
1482 IWineD3DSurfaceImpl_SetFormat