wined3d: Implement WineD3DSurface palette methods.
[wine/gsoc_dplay.git] / dlls / wined3d / surface.c
blob5c95a7e26676da77d9e2d7b202ad0dd0fcb52004
1 /*
2 * IWineD3DSurface Implementation
4 * Copyright 2000-2001 TransGaming Technologies Inc.
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2002-2003 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006 Stefan Dösinger for CodeWeavers
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include "config.h"
27 #include "wine/port.h"
28 #include "wined3d_private.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
31 #define GLINFO_LOCATION ((IWineD3DImpl *)(((IWineD3DDeviceImpl *)This->resource.wineD3DDevice)->wineD3D))->gl_info
33 /* *******************************************
34 IWineD3DSurface IUnknown parts follow
35 ******************************************* */
36 HRESULT WINAPI IWineD3DSurfaceImpl_QueryInterface(IWineD3DSurface *iface, REFIID riid, LPVOID *ppobj)
38 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
39 /* Warn ,but be nice about things */
40 TRACE("(%p)->(%s,%p)\n", This,debugstr_guid(riid),ppobj);
41 if (riid == NULL) {
42 ERR("Probably FIXME: Calling query interface with NULL riid\n");
44 if (IsEqualGUID(riid, &IID_IUnknown)
45 || IsEqualGUID(riid, &IID_IWineD3DBase)
46 || IsEqualGUID(riid, &IID_IWineD3DResource)
47 || IsEqualGUID(riid, &IID_IWineD3DSurface)) {
48 IUnknown_AddRef((IUnknown*)iface);
49 *ppobj = This;
50 return S_OK;
52 *ppobj = NULL;
53 return E_NOINTERFACE;
56 ULONG WINAPI IWineD3DSurfaceImpl_AddRef(IWineD3DSurface *iface) {
57 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
58 ULONG ref = InterlockedIncrement(&This->resource.ref);
59 TRACE("(%p) : AddRef increasing from %ld\n", This,ref - 1);
60 return ref;
63 ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface) {
64 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
65 ULONG ref = InterlockedDecrement(&This->resource.ref);
66 TRACE("(%p) : Releasing from %ld\n", This, ref + 1);
67 if (ref == 0) {
68 TRACE("(%p) : cleaning up\n", This);
69 if (This->glDescription.textureName != 0) { /* release the openGL texture.. */
70 ENTER_GL();
71 TRACE("Deleting texture %d\n", This->glDescription.textureName);
72 glDeleteTextures(1, &This->glDescription.textureName);
73 LEAVE_GL();
76 if(This->Flags & SFLAG_DIBSECTION) {
77 /* Release the DC */
78 SelectObject(This->hDC, This->dib.holdbitmap);
79 DeleteDC(This->hDC);
80 /* Release the DIB section */
81 DeleteObject(This->dib.DIBsection);
82 This->dib.bitmap_data = NULL;
83 This->resource.allocatedMemory = NULL;
86 IWineD3DResourceImpl_CleanUp((IWineD3DResource *)iface);
88 TRACE("(%p) Released\n", This);
89 HeapFree(GetProcessHeap(), 0, This);
92 return ref;
95 /* ****************************************************
96 IWineD3DSurface IWineD3DResource parts follow
97 **************************************************** */
98 HRESULT WINAPI IWineD3DSurfaceImpl_GetDevice(IWineD3DSurface *iface, IWineD3DDevice** ppDevice) {
99 return IWineD3DResourceImpl_GetDevice((IWineD3DResource *)iface, ppDevice);
102 HRESULT WINAPI IWineD3DSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
103 return IWineD3DResourceImpl_SetPrivateData((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
106 HRESULT WINAPI IWineD3DSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
107 return IWineD3DResourceImpl_GetPrivateData((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
110 HRESULT WINAPI IWineD3DSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid) {
111 return IWineD3DResourceImpl_FreePrivateData((IWineD3DResource *)iface, refguid);
114 DWORD WINAPI IWineD3DSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) {
115 return IWineD3DResourceImpl_SetPriority((IWineD3DResource *)iface, PriorityNew);
118 DWORD WINAPI IWineD3DSurfaceImpl_GetPriority(IWineD3DSurface *iface) {
119 return IWineD3DResourceImpl_GetPriority((IWineD3DResource *)iface);
122 void WINAPI IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface *iface) {
123 /* TODO: re-write the way textures and managed,
124 * use a 'opengl context manager' to manage RenderTarget surfaces
125 ** *********************************************************/
127 /* TODO: check for locks */
128 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
129 IWineD3DBaseTexture *baseTexture = NULL;
130 TRACE("(%p)Checking to see if the container is a base texture\n", This);
131 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
132 TRACE("Passing to conatiner\n");
133 IWineD3DBaseTexture_PreLoad(baseTexture);
134 IWineD3DBaseTexture_Release(baseTexture);
135 } else {
136 TRACE("(%p) : About to load surface\n", This);
137 ENTER_GL();
138 #if 0 /* TODO: context manager support */
139 IWineD3DContextManager_PushState(This->contextManager, GL_TEXTURE_2D, ENABLED, NOW /* make sure the state is applied now */);
140 #endif
141 glEnable(This->glDescription.target);/* make sure texture support is enabled in this context */
142 if (This->glDescription.level == 0 && This->glDescription.textureName == 0) {
143 glGenTextures(1, &This->glDescription.textureName);
144 checkGLcall("glGenTextures");
145 TRACE("Surface %p given name %d\n", This, This->glDescription.textureName);
146 glBindTexture(This->glDescription.target, This->glDescription.textureName);
147 checkGLcall("glBindTexture");
148 IWineD3DSurface_LoadTexture(iface);
149 /* This is where we should be reducing the amount of GLMemoryUsed */
150 } else {
151 if (This->glDescription.level == 0) {
152 glBindTexture(This->glDescription.target, This->glDescription.textureName);
153 checkGLcall("glBindTexture");
154 IWineD3DSurface_LoadTexture(iface);
155 } else if (This->glDescription.textureName != 0) { /* NOTE: the level 0 surface of a mpmapped texture must be loaded first! */
156 /* assume this is a coding error not a real error for now */
157 FIXME("Mipmap surface has a glTexture bound to it!\n");
160 if (This->resource.pool == WINED3DPOOL_DEFAULT) {
161 /* Tell opengl to try and keep this texture in video ram (well mostly) */
162 GLclampf tmp;
163 tmp = 0.9f;
164 glPrioritizeTextures(1, &This->glDescription.textureName, &tmp);
166 /* TODO: disable texture support, if it wastn't enabled when we entered. */
167 #if 0 /* TODO: context manager support */
168 IWineD3DContextManager_PopState(This->contextManager, GL_TEXTURE_2D, DISABLED,DELAYED
169 /* we don't care when the state is disabled(if atall) */);
170 #endif
171 LEAVE_GL();
173 return;
176 WINED3DRESOURCETYPE WINAPI IWineD3DSurfaceImpl_GetType(IWineD3DSurface *iface) {
177 TRACE("(%p) : calling resourceimpl_GetType\n", iface);
178 return IWineD3DResourceImpl_GetType((IWineD3DResource *)iface);
181 HRESULT WINAPI IWineD3DSurfaceImpl_GetParent(IWineD3DSurface *iface, IUnknown **pParent) {
182 TRACE("(%p) : calling resourceimpl_GetParent\n", iface);
183 return IWineD3DResourceImpl_GetParent((IWineD3DResource *)iface, pParent);
186 /* ******************************************************
187 IWineD3DSurface IWineD3DSurface parts follow
188 ****************************************************** */
190 HRESULT WINAPI IWineD3DSurfaceImpl_GetContainerParent(IWineD3DSurface* iface, IUnknown **ppContainerParent) {
191 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
193 TRACE("(%p) : ppContainerParent %p)\n", This, ppContainerParent);
195 if (!ppContainerParent) {
196 ERR("(%p) : Called without a valid ppContainerParent.\n", This);
199 if (This->container) {
200 IWineD3DBase_GetParent(This->container, ppContainerParent);
201 if (!ppContainerParent) {
202 /* WineD3D objects should always have a parent */
203 ERR("(%p) : GetParent returned NULL\n", This);
205 IUnknown_Release(*ppContainerParent); /* GetParent adds a reference; we want just the pointer */
206 } else {
207 *ppContainerParent = NULL;
210 return WINED3D_OK;
213 HRESULT WINAPI IWineD3DSurfaceImpl_GetContainer(IWineD3DSurface* iface, REFIID riid, void** ppContainer) {
214 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
215 IWineD3DBase *container = 0;
217 TRACE("(This %p, riid %s, ppContainer %p)\n", This, debugstr_guid(riid), ppContainer);
219 if (!ppContainer) {
220 ERR("Called without a valid ppContainer.\n");
223 /** From MSDN:
224 * If the surface is created using CreateImageSurface/CreateOffscreenPlainSurface, CreateRenderTarget,
225 * or CreateDepthStencilSurface, the surface is considered stand alone. In this case,
226 * GetContainer will return the Direct3D device used to create the surface.
228 if (This->container) {
229 container = This->container;
230 } else {
231 container = (IWineD3DBase *)This->resource.wineD3DDevice;
234 TRACE("Relaying to QueryInterface\n");
235 if (IUnknown_QueryInterface(container, riid, ppContainer) != S_OK)
236 return WINED3DERR_INVALIDCALL;
238 return WINED3D_OK;
241 HRESULT WINAPI IWineD3DSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc) {
242 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
244 TRACE("(%p) : copying into %p\n", This, pDesc);
245 if(pDesc->Format != NULL) *(pDesc->Format) = This->resource.format;
246 if(pDesc->Type != NULL) *(pDesc->Type) = This->resource.resourceType;
247 if(pDesc->Usage != NULL) *(pDesc->Usage) = This->resource.usage;
248 if(pDesc->Pool != NULL) *(pDesc->Pool) = This->resource.pool;
249 if(pDesc->Size != NULL) *(pDesc->Size) = This->resource.size; /* dx8 only */
250 if(pDesc->MultiSampleType != NULL) *(pDesc->MultiSampleType) = This->currentDesc.MultiSampleType;
251 if(pDesc->MultiSampleQuality != NULL) *(pDesc->MultiSampleQuality) = This->currentDesc.MultiSampleQuality;
252 if(pDesc->Width != NULL) *(pDesc->Width) = This->currentDesc.Width;
253 if(pDesc->Height != NULL) *(pDesc->Height) = This->currentDesc.Height;
254 return WINED3D_OK;
257 void WINAPI IWineD3DSurfaceImpl_SetGlTextureDesc(IWineD3DSurface *iface, UINT textureName, int target) {
258 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
259 TRACE("(%p) : setting textureName %u, target %i\n", This, textureName, target);
260 if (This->glDescription.textureName == 0 && textureName != 0) {
261 This->Flags |= SFLAG_DIRTY;
262 IWineD3DSurface_AddDirtyRect(iface, NULL);
264 This->glDescription.textureName = textureName;
265 This->glDescription.target = target;
268 void WINAPI IWineD3DSurfaceImpl_GetGlDesc(IWineD3DSurface *iface, glDescriptor **glDescription) {
269 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
270 TRACE("(%p) : returning %p\n", This, &This->glDescription);
271 *glDescription = &This->glDescription;
274 /* TODO: think about moving this down to resource? */
275 const void *WINAPI IWineD3DSurfaceImpl_GetData(IWineD3DSurface *iface) {
276 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
277 /* 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 */
278 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM) {
279 FIXME(" (%p)Attempting to get system memory for a non-system memory texture\n", iface);
281 return (CONST void*)(This->resource.allocatedMemory);
284 HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
285 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
286 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
287 IWineD3DSwapChainImpl *swapchain = NULL;
288 static UINT messages = 0; /* holds flags to disable fixme messages */
290 /* fixme: should we really lock as such? */
291 if((This->Flags & (SFLAG_INTEXTURE | SFLAG_INPBUFFER)) ==
292 (SFLAG_INTEXTURE | SFLAG_INPBUFFER) ) {
293 FIXME("Warning: Surface is in texture memory or pbuffer\n");
294 This->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INPBUFFER);
297 if (!(This->Flags & SFLAG_LOCKABLE)) {
298 /* Note: UpdateTextures calls CopyRects which calls this routine to populate the
299 texture regions, and since the destination is an unlockable region we need
300 to tolerate this */
301 TRACE("Warning: trying to lock unlockable surf@%p\n", This);
302 /*return WINED3DERR_INVALIDCALL; */
305 if (This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
306 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
308 if (swapchain != NULL || iface == myDevice->renderTarget || iface == myDevice->depthStencilBuffer) {
309 if (swapchain != NULL && iface == swapchain->backBuffer) {
310 TRACE("(%p, backBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
311 } else if (swapchain != NULL && iface == swapchain->frontBuffer) {
312 TRACE("(%p, frontBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
313 } else if (iface == myDevice->renderTarget) {
314 TRACE("(%p, renderTarget) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
315 } else if (iface == myDevice->depthStencilBuffer) {
316 TRACE("(%p, stencilBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
319 if (NULL != swapchain) {
320 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
322 swapchain = NULL;
324 } else {
325 TRACE("(%p) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
328 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
330 if (NULL == pRect) {
331 pLockedRect->pBits = This->resource.allocatedMemory;
332 This->lockedRect.left = 0;
333 This->lockedRect.top = 0;
334 This->lockedRect.right = This->currentDesc.Width;
335 This->lockedRect.bottom = This->currentDesc.Height;
336 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);
337 } else {
338 TRACE("Lock Rect (%p) = l %ld, t %ld, r %ld, b %ld\n", pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
340 if (This->resource.format == WINED3DFMT_DXT1) { /* DXT1 is half byte per pixel */
341 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
342 } else {
343 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
345 This->lockedRect.left = pRect->left;
346 This->lockedRect.top = pRect->top;
347 This->lockedRect.right = pRect->right;
348 This->lockedRect.bottom = pRect->bottom;
351 if (This->Flags & SFLAG_NONPOW2) {
352 TRACE("Locking non-power 2 texture\n");
355 if (0 == This->resource.usage || This->resource.usage & WINED3DUSAGE_DYNAMIC) {
356 /* classic surface TODO: non 2d surfaces?
357 These resources may be POOL_SYSTEMMEM, so they must not access the device */
358 TRACE("locking an ordinarary surface\n");
359 /* Check to see if memory has already been allocated from the surface*/
360 if ((NULL == This->resource.allocatedMemory) ||
361 (This->Flags & SFLAG_NEWDC) ){ /* TODO: check to see if an update has been performed on the surface (an update could just clobber allocatedMemory */
362 /* Non-system memory surfaces */
364 /*Surface has no memory currently allocated to it!*/
365 TRACE("(%p) Locking rect\n" , This);
366 if(!This->resource.allocatedMemory) {
367 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 , This->pow2Size);
369 if (0 != This->glDescription.textureName) {
370 /* Now I have to copy thing bits back */
371 This->Flags |= SFLAG_ACTIVELOCK; /* When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory */
372 /* TODO: make activeLock a bit more intelligent, maybe implement a method to purge the texture memory. */
373 ENTER_GL();
375 /* Make sure that the texture is loaded */
376 IWineD3DSurface_PreLoad(iface); /* Make sure there is a texture to bind! */
378 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);
380 if (This->resource.format == WINED3DFMT_DXT1 ||
381 This->resource.format == WINED3DFMT_DXT2 ||
382 This->resource.format == WINED3DFMT_DXT3 ||
383 This->resource.format == WINED3DFMT_DXT4 ||
384 This->resource.format == WINED3DFMT_DXT5) {
385 TRACE("Locking a compressed texture\n");
386 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) { /* we can assume this as the texture would not have been created otherwise */
387 GL_EXTCALL(glGetCompressedTexImageARB)(This->glDescription.target,
388 This->glDescription.level,
389 This->resource.allocatedMemory);
391 } else {
392 FIXME("(%p) attempting to lock a compressed texture when texture compression isn't supported by opengl\n", This);
394 } else {
395 glGetTexImage(This->glDescription.target,
396 This->glDescription.level,
397 This->glDescription.glFormat,
398 This->glDescription.glType,
399 This->resource.allocatedMemory);
400 vcheckGLcall("glGetTexImage");
401 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
402 /* some games (e.g. warhammer 40k) don't work with the odd pitchs properly, preventing
403 the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
404 repack the texture so that the bpp * width pitch can be used instead of the bpp * pow2width.
406 Were doing this...
408 instead of boxing the texture :
409 |<-texture width ->| -->pow2width| /\
410 |111111111111111111| | |
411 |222 Texture 222222| boxed empty | texture height
412 |3333 Data 33333333| | |
413 |444444444444444444| | \/
414 ----------------------------------- |
415 | boxed empty | boxed empty | pow2height
416 | | | \/
417 -----------------------------------
420 were repacking the data to the expected texture width
422 |<-texture width ->| -->pow2width| /\
423 |111111111111111111222222222222222| |
424 |222333333333333333333444444444444| texture height
425 |444444 | |
426 | | \/
427 | | |
428 | empty | pow2height
429 | | \/
430 -----------------------------------
432 == is the same as
434 |<-texture width ->| /\
435 |111111111111111111|
436 |222222222222222222|texture height
437 |333333333333333333|
438 |444444444444444444| \/
439 --------------------
441 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.
443 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.
445 if (This->Flags & SFLAG_NONPOW2) {
446 BYTE* dataa, *datab;
447 int pitcha = 0, pitchb = 0;
448 int y;
449 pitcha = This->bytesPerPixel * This->currentDesc.Width;
450 pitchb = This->bytesPerPixel * This->pow2Width;
451 datab = dataa = This->resource.allocatedMemory;
452 FIXME("(%p) : Repacking the surface data from pitch %d to pitch %d\n", This, pitcha, pitchb);
453 for (y = 1 ; y < This->currentDesc.Height; y++) {
454 dataa += pitcha; /* skip the first row */
455 datab += pitchb;
456 memcpy(dataa, datab, pitcha);
461 LEAVE_GL();
463 } else { /* Nothing to do */
464 TRACE("Memory %p already allocted for texture\n", This->resource.allocatedMemory);
467 if (NULL == pRect) {
468 pLockedRect->pBits = This->resource.allocatedMemory;
469 } else{
470 if (This->resource.format == D3DFMT_DXT1) { /* DXT1 is half byte per pixel */
471 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
472 } else {
473 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
477 } else if (WINED3DUSAGE_RENDERTARGET & This->resource.usage && !(Flags&WINED3DLOCK_DISCARD)) { /* render surfaces */
479 GLint prev_store;
480 GLint prev_read;
481 BOOL notInContext = FALSE;
482 IWineD3DSwapChainImpl *targetSwapChain = NULL;
485 ENTER_GL();
488 * for render->surface copy begin to begin of allocatedMemory
489 * unlock can be more easy
492 TRACE("locking a render target\n");
494 if (This->resource.allocatedMemory == NULL)
495 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 ,This->resource.size);
497 This->Flags |= SFLAG_ACTIVELOCK; /*When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory*/
498 pLockedRect->pBits = This->resource.allocatedMemory;
500 glFlush();
501 vcheckGLcall("glFlush");
502 glGetIntegerv(GL_READ_BUFFER, &prev_read);
503 vcheckGLcall("glIntegerv");
504 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
505 vcheckGLcall("glIntegerv");
507 /* Here's what we have to do:
508 See if the swapchain has the same context as the renderTarget or the surface is the render target.
509 Otherwise, see if were sharing a context with the implicit swapchain (because we're using a shared context model!)
510 and use the front back buffer as required.
511 if not, we need to switch contexts and then switchback at the end.
513 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
514 IWineD3DSurface_GetContainer(myDevice->renderTarget, &IID_IWineD3DSwapChain, (void **)&targetSwapChain);
516 /* 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! */
517 if ((swapchain == targetSwapChain && targetSwapChain != NULL) || iface == myDevice->renderTarget) {
518 if (iface == myDevice->renderTarget || iface == swapchain->backBuffer) {
519 TRACE("locking back buffer\n");
520 glReadBuffer(GL_BACK);
521 } else if (iface == swapchain->frontBuffer) {
522 TRACE("locking front\n");
523 glReadBuffer(GL_FRONT);
524 } else if (iface == myDevice->depthStencilBuffer) {
525 FIXME("Stencil Buffer lock unsupported for now\n");
526 } else {
527 FIXME("(%p) Shouldn't have got here!\n", This);
528 glReadBuffer(GL_BACK);
530 } else if (swapchain != NULL) {
531 IWineD3DSwapChainImpl *implSwapChain;
532 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
533 if (swapchain->glCtx == implSwapChain->render_ctx && swapchain->drawable == implSwapChain->win) {
534 /* This will fail for the implicit swapchain, which is why there needs to be a context manager */
535 if (iface == swapchain->backBuffer) {
536 glReadBuffer(GL_BACK);
537 } else if (iface == swapchain->frontBuffer) {
538 glReadBuffer(GL_FRONT);
539 } else if (iface == myDevice->depthStencilBuffer) {
540 FIXME("Stencil Buffer lock unsupported for now\n");
541 } else {
542 FIXME("Should have got here!\n");
543 glReadBuffer(GL_BACK);
545 } else {
546 /* We need to switch contexts to be able to read the buffer!!! */
547 FIXME("The buffer requested isn't in the current openGL context\n");
548 notInContext = TRUE;
549 /* TODO: check the contexts, to see if were shared with the current context */
551 IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
553 if (swapchain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
554 if (targetSwapChain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)targetSwapChain);
557 /** the depth stencil in openGL has a format of GL_FLOAT
558 * which should be good for WINED3DFMT_D16_LOCKABLE
559 * and WINED3DFMT_D16
560 * it is unclear what format the stencil buffer is in except.
561 * 'Each index is converted to fixed point...
562 * If GL_MAP_STENCIL is GL_TRUE, indices are replaced by their
563 * mappings in the table GL_PIXEL_MAP_S_TO_S.
564 * glReadPixels(This->lockedRect.left,
565 * This->lockedRect.bottom - j - 1,
566 * This->lockedRect.right - This->lockedRect.left,
567 * 1,
568 * GL_DEPTH_COMPONENT,
569 * type,
570 * (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
571 *****************************************/
572 if (!notInContext) { /* Only read the buffer if it's in the current context */
573 long j;
574 #if 0
575 /* 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,
576 * This is on an ATI9600, and may be format dependent, anyhow this hack makes this demo dx9_2d_demo_game
577 * run ten times faster!
578 * ************************************/
579 BOOL ati_performance_hack = FALSE;
580 ati_performance_hack = (This->lockedRect.bottom - This->lockedRect.top > 10) || (This->lockedRect.right - This->lockedRect.left > 10)? TRUE: FALSE;
581 #endif
582 if ((This->lockedRect.left == 0 && This->lockedRect.top == 0 &&
583 This->lockedRect.right == This->currentDesc.Width
584 && This->lockedRect.bottom == This->currentDesc.Height)) {
585 glReadPixels(0, 0,
586 This->currentDesc.Width,
587 This->currentDesc.Height,
588 This->glDescription.glFormat,
589 This->glDescription.glType,
590 (char *)pLockedRect->pBits);
591 } else if (This->lockedRect.left == 0 && This->lockedRect.right == This->currentDesc.Width) {
592 glReadPixels(0,
593 This->lockedRect.top,
594 This->currentDesc.Width,
595 This->currentDesc.Height,
596 This->glDescription.glFormat,
597 This->glDescription.glType,
598 (char *)pLockedRect->pBits);
599 } else{
601 for (j = This->lockedRect.top; j < This->lockedRect.bottom - This->lockedRect.top; ++j) {
602 glReadPixels(This->lockedRect.left,
603 This->lockedRect.bottom - j - 1,
604 This->lockedRect.right - This->lockedRect.left,
606 This->glDescription.glFormat,
607 This->glDescription.glType,
608 (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
612 vcheckGLcall("glReadPixels");
613 TRACE("Resetting buffer\n");
614 glReadBuffer(prev_read);
615 vcheckGLcall("glReadBuffer");
617 LEAVE_GL();
619 } else if (WINED3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
621 if (!messages & 1) {
622 FIXME("TODO stencil depth surface locking surf%p usage(%lu)\n", This, This->resource.usage);
625 glReadPixels(This->lockedRect.left,
626 This->lockedRect.bottom - j - 1,
627 This->lockedRect.right - This->lockedRect.left,
629 GL_STENCIL_INDEX or GL_DEPTH_COMPONENT
633 messages |= 1;
635 } else {
636 FIXME("unsupported locking to surface surf@%p usage(%lu)\n", This, This->resource.usage);
639 if (Flags & (WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY)) {
640 /* Don't dirtify */
641 } else {
642 IWineD3DBaseTexture *pBaseTexture;
644 * Dirtify on lock
645 * as seen in msdn docs
647 IWineD3DSurface_AddDirtyRect(iface, &This->lockedRect);
649 /** Dirtify Container if needed */
650 if (WINED3D_OK == IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&pBaseTexture) && pBaseTexture != NULL) {
651 TRACE("Making container dirty\n");
652 IWineD3DBaseTexture_SetDirty(pBaseTexture, TRUE);
653 IWineD3DBaseTexture_Release(pBaseTexture);
654 } else {
655 TRACE("Surface is standalone, no need to dirty the container\n");
659 TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect->pBits, pLockedRect->Pitch, This->Flags & SFLAG_DIRTY ? 0 : 1);
661 This->Flags |= SFLAG_LOCKED;
662 return WINED3D_OK;
665 HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
666 GLint skipBytes = 0;
667 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
668 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
669 const char *buffername = "";
670 IWineD3DSwapChainImpl *swapchain = NULL;
672 if (!(This->Flags & SFLAG_LOCKED)) {
673 WARN("trying to Unlock an unlocked surf@%p\n", This);
674 return WINED3DERR_INVALIDCALL;
677 if (WINED3DUSAGE_RENDERTARGET & This->resource.usage) {
678 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
680 if ((swapchain != NULL) && iface == swapchain->backBuffer) {
681 buffername = "backBuffer";
682 } else if ((swapchain != NULL) && iface == swapchain->frontBuffer) {
683 buffername = "frontBuffer";
684 } else if (iface == myDevice->depthStencilBuffer) {
685 buffername = "depthStencilBuffer";
686 } else if (iface == myDevice->renderTarget) {
687 buffername = "renderTarget";
691 if (swapchain != NULL) {
692 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
695 TRACE("(%p %s) : dirtyfied(%d)\n", This, buffername, This->Flags & SFLAG_DIRTY ? 1 : 0);
697 if (!(This->Flags & SFLAG_DIRTY)) {
698 TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
699 goto unlock_end;
702 if (0 == This->resource.usage) { /* classic surface */
704 * nothing to do
705 * waiting to reload the surface via IDirect3DDevice8::UpdateTexture
707 } else if (WINED3DUSAGE_RENDERTARGET & This->resource.usage) { /* render surfaces */
709 /****************************
710 * TODO: Render targets are 'special' and
711 * ?some? locking needs to be passed onto the context manager
712 * so that it becomes possible to use auxiliary buffers, pbuffers
713 * render-to-texture, shared, cached contexts etc...
714 * ****************************/
715 IWineD3DSwapChainImpl *implSwapChain;
716 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
718 if (iface == implSwapChain->backBuffer || iface == implSwapChain->frontBuffer || iface == myDevice->renderTarget) {
719 GLint prev_store;
720 GLint prev_draw;
721 GLint prev_rasterpos[4];
723 /* Some drivers(radeon dri, others?) don't like exceptions during
724 * glDrawPixels. If the surface is a DIB section, it might be in GDIMode
725 * after ReleaseDC. Reading it will cause an exception, which x11drv will
726 * catch to put the dib section in InSync mode, which leads to a crash
727 * and a blocked x server on my radeon card.
729 * The following lines read the dib section so it is put in inSync mode
730 * before glDrawPixels is called and the crash is prevented. There won't
731 * be any interfering gdi accesses, because UnlockRect is called from
732 * ReleaseDC, and the app won't use the dc any more afterwards.
734 if(This->Flags & SFLAG_DIBSECTION) {
735 volatile BYTE read;
736 read = This->resource.allocatedMemory[0];
739 ENTER_GL();
741 glFlush();
742 vcheckGLcall("glFlush");
743 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
744 vcheckGLcall("glIntegerv");
745 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
746 vcheckGLcall("glIntegerv");
747 glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
748 vcheckGLcall("glIntegerv");
749 glPixelZoom(1.0, -1.0);
750 vcheckGLcall("glPixelZoom");
752 /* glDrawPixels transforms the raster position as though it was a vertex -
753 we want to draw at screen position 0,0 - Set up ortho (rhw) mode as
754 per drawprim (and leave set - it will sort itself out due to last_was_rhw */
755 if ( (!myDevice->last_was_rhw) || (myDevice->viewport_changed) ) {
757 double X, Y, height, width, minZ, maxZ;
758 myDevice->last_was_rhw = TRUE;
759 myDevice->viewport_changed = FALSE;
761 /* Transformed already into viewport coordinates, so we do not need transform
762 matrices. Reset all matrices to identity and leave the default matrix in world
763 mode. */
764 glMatrixMode(GL_MODELVIEW);
765 checkGLcall("glMatrixMode");
766 glLoadIdentity();
767 checkGLcall("glLoadIdentity");
769 glMatrixMode(GL_PROJECTION);
770 checkGLcall("glMatrixMode");
771 glLoadIdentity();
772 checkGLcall("glLoadIdentity");
774 /* Set up the viewport to be full viewport */
775 X = myDevice->stateBlock->viewport.X;
776 Y = myDevice->stateBlock->viewport.Y;
777 height = myDevice->stateBlock->viewport.Height;
778 width = myDevice->stateBlock->viewport.Width;
779 minZ = myDevice->stateBlock->viewport.MinZ;
780 maxZ = myDevice->stateBlock->viewport.MaxZ;
781 TRACE("Calling glOrtho with %f, %f, %f, %f\n", width, height, -minZ, -maxZ);
782 glOrtho(X, X + width, Y + height, Y, -minZ, -maxZ);
783 checkGLcall("glOrtho");
785 /* Window Coord 0 is the middle of the first pixel, so translate by half
786 a pixel (See comment above glTranslate below) */
787 glTranslatef(0.5, 0.5, 0);
788 checkGLcall("glTranslatef(0.5, 0.5, 0)");
791 if (iface == implSwapChain->backBuffer || iface == myDevice->renderTarget) {
792 glDrawBuffer(GL_BACK);
793 } else if (iface == implSwapChain->frontBuffer) {
794 glDrawBuffer(GL_FRONT);
797 vcheckGLcall("glDrawBuffer");
799 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
800 glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
801 glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width);
803 /* And back buffers are not blended */
804 glDisable(GL_BLEND);
806 glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
807 vcheckGLcall("glRasterPos2f");
808 switch (This->resource.format) {
809 case WINED3DFMT_X4R4G4B4:
811 int size;
812 unsigned short *data;
813 data = (unsigned short *)This->resource.allocatedMemory;
814 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
815 while(size > 0) {
816 *data |= 0xF000;
817 data++;
818 size--;
821 case WINED3DFMT_A4R4G4B4:
823 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
824 GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4_REV, This->resource.allocatedMemory);
825 vcheckGLcall("glDrawPixels");
827 break;
828 case WINED3DFMT_R5G6B5:
830 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
831 GL_RGB, GL_UNSIGNED_SHORT_5_6_5, This->resource.allocatedMemory);
832 vcheckGLcall("glDrawPixels");
834 break;
835 case WINED3DFMT_X1R5G5B5:
837 int size;
838 unsigned short *data;
839 data = (unsigned short *)This->resource.allocatedMemory;
840 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
841 while(size > 0) {
842 *data |= 0x8000;
843 data++;
844 size--;
847 case WINED3DFMT_A1R5G5B5:
849 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
850 GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, This->resource.allocatedMemory);
851 vcheckGLcall("glDrawPixels");
853 break;
854 case WINED3DFMT_R8G8B8:
856 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
857 GL_RGB, GL_UNSIGNED_BYTE, This->resource.allocatedMemory);
858 vcheckGLcall("glDrawPixels");
860 break;
861 case WINED3DFMT_X8R8G8B8: /* make sure the X byte is set to alpha on, since it
862 could be any random value this fixes the intro move in Pirates! */
864 int size;
865 unsigned int *data;
866 data = (unsigned int *)This->resource.allocatedMemory;
867 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
868 while(size > 0) {
869 *data |= 0xFF000000;
870 data++;
871 size--;
874 case WINED3DFMT_A8R8G8B8:
876 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
877 vcheckGLcall("glPixelStorei");
878 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
879 GL_BGRA, GL_UNSIGNED_BYTE, This->resource.allocatedMemory);
880 vcheckGLcall("glDrawPixels");
881 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
882 vcheckGLcall("glPixelStorei");
884 break;
885 case WINED3DFMT_A2R10G10B10:
887 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
888 vcheckGLcall("glPixelStorei");
889 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
890 GL_BGRA, GL_UNSIGNED_INT_2_10_10_10_REV, This->resource.allocatedMemory);
891 vcheckGLcall("glDrawPixels");
892 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
893 vcheckGLcall("glPixelStorei");
895 break;
896 default:
897 FIXME("Unsupported Format %u in locking func\n", This->resource.format);
900 glPixelZoom(1.0,1.0);
901 vcheckGLcall("glPixelZoom");
902 glDrawBuffer(prev_draw);
903 vcheckGLcall("glDrawBuffer");
904 glRasterPos3iv(&prev_rasterpos[0]);
905 vcheckGLcall("glRasterPos3iv");
907 /* Reset to previous pack row length / blending state */
908 glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
909 if (myDevice->stateBlock->renderState[D3DRS_ALPHABLENDENABLE]) glEnable(GL_BLEND);
911 LEAVE_GL();
913 /** restore clean dirty state */
914 IWineD3DSurface_CleanDirtyRect(iface);
916 } else {
917 FIXME("unsupported unlocking to Rendering surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
919 IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
921 } else if (WINED3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
923 if (iface == myDevice->depthStencilBuffer) {
924 FIXME("TODO stencil depth surface unlocking surf@%p usage(%lu)\n", This, This->resource.usage);
925 } else {
926 FIXME("unsupported unlocking to StencilDepth surface surf@%p usage(%lu)\n", This, This->resource.usage);
929 } else {
930 FIXME("unsupported unlocking to surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
933 unlock_end:
934 This->Flags &= ~SFLAG_LOCKED;
935 memset(&This->lockedRect, 0, sizeof(RECT));
936 return WINED3D_OK;
939 HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
940 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
941 WINED3DLOCKED_RECT lock;
942 UINT usage;
943 BITMAPINFO* b_info;
944 HDC ddc;
945 DWORD *masks;
946 HRESULT hr;
948 TRACE("(%p)->(%p)\n",This,pHDC);
950 /* Give more detailed info for ddraw */
951 if (This->Flags & SFLAG_DCINUSE)
952 return DDERR_DCALREADYCREATED;
954 /* Can't GetDC if the surface is locked */
955 if (This->Flags & SFLAG_LOCKED)
956 return WINED3DERR_INVALIDCALL;
958 memset(&lock, 0, sizeof(lock)); /* To be sure */
960 /* Create a DIB section if there isn't a hdc yet */
961 if(!This->hDC)
963 RGBQUAD col[256];
965 if(This->Flags & SFLAG_ACTIVELOCK)
967 ERR("Creating a DIB section while a lock is active. Uncertain consequences\n");
970 switch (This->bytesPerPixel)
972 case 2:
973 case 4:
974 /* Allocate extra space to store the RGB bit masks. */
975 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
976 break;
978 case 3:
979 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
980 break;
982 default:
983 /* Allocate extra space for a palette. */
984 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
985 sizeof(BITMAPINFOHEADER)
986 + sizeof(RGBQUAD)
987 * (1 << (This->bytesPerPixel * 8)));
988 break;
991 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
992 b_info->bmiHeader.biWidth = This->pow2Width;
993 b_info->bmiHeader.biHeight = -This->pow2Height;
994 b_info->bmiHeader.biPlanes = 1;
995 b_info->bmiHeader.biBitCount = This->bytesPerPixel * 8;
997 b_info->bmiHeader.biSizeImage = This->resource.size;
999 b_info->bmiHeader.biXPelsPerMeter = 0;
1000 b_info->bmiHeader.biYPelsPerMeter = 0;
1001 b_info->bmiHeader.biClrUsed = 0;
1002 b_info->bmiHeader.biClrImportant = 0;
1004 /* Get the bit masks */
1005 masks = (DWORD *) &(b_info->bmiColors);
1006 switch (This->resource.format)
1008 case WINED3DFMT_R8G8B8:
1009 usage = DIB_RGB_COLORS;
1010 b_info->bmiHeader.biCompression = BI_RGB;
1011 break;
1013 case WINED3DFMT_X1R5G5B5:
1014 case WINED3DFMT_A1R5G5B5:
1015 case WINED3DFMT_A4R4G4B4:
1016 case WINED3DFMT_X4R4G4B4:
1017 case WINED3DFMT_R3G3B2:
1018 case WINED3DFMT_A8R3G3B2:
1019 case WINED3DFMT_A2B10G10R10:
1020 case WINED3DFMT_A8B8G8R8:
1021 case WINED3DFMT_X8B8G8R8:
1022 case WINED3DFMT_A2R10G10B10:
1023 case WINED3DFMT_R5G6B5:
1024 case WINED3DFMT_A16B16G16R16:
1025 usage = 0;
1026 b_info->bmiHeader.biCompression = BI_BITFIELDS;
1027 masks[0] = get_bitmask_red(This->resource.format);
1028 masks[1] = get_bitmask_green(This->resource.format);
1029 masks[2] = get_bitmask_blue(This->resource.format);
1030 break;
1032 default:
1033 /* Don't know palette */
1034 b_info->bmiHeader.biCompression = BI_RGB;
1035 usage = 0;
1036 break;
1039 ddc = CreateDCA("DISPLAY", NULL, NULL, NULL);
1040 if (ddc == 0)
1042 HeapFree(GetProcessHeap(), 0, b_info);
1043 return HRESULT_FROM_WIN32(GetLastError());
1046 TRACE("Creating a DIB section with size %ldx%ldx%d, size=%ld\n", b_info->bmiHeader.biWidth, b_info->bmiHeader.biHeight, b_info->bmiHeader.biBitCount, b_info->bmiHeader.biSizeImage);
1047 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
1048 DeleteDC(ddc);
1050 if (!This->dib.DIBsection)
1052 ERR("CreateDIBSection failed!\n");
1053 return HRESULT_FROM_WIN32(GetLastError());
1055 HeapFree(GetProcessHeap(), 0, b_info);
1057 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
1059 /* copy the existing surface to the dib section */
1060 if(This->resource.allocatedMemory)
1062 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->resource.size);
1063 /* We won't need that any more */
1064 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1067 /* Use the dib section from now on */
1068 This->resource.allocatedMemory = This->dib.bitmap_data;
1070 /* Now allocate a HDC */
1071 This->hDC = CreateCompatibleDC(0);
1072 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
1073 TRACE("using wined3d palette %p\n", This->palette);
1074 SelectPalette(This->hDC,
1075 This->palette ? This->palette->hpal : 0,
1076 FALSE);
1078 if(This->resource.format == WINED3DFMT_P8 ||
1079 This->resource.format == WINED3DFMT_A8P8)
1081 unsigned int n;
1082 if(This->palette)
1084 PALETTEENTRY ent[256];
1086 GetPaletteEntries(This->palette->hpal, 0, 256, ent);
1087 for (n=0; n<256; n++)
1089 col[n].rgbRed = ent[n].peRed;
1090 col[n].rgbGreen = ent[n].peGreen;
1091 col[n].rgbBlue = ent[n].peBlue;
1092 col[n].rgbReserved = 0;
1095 else
1097 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1099 for (n=0; n<256; n++)
1101 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
1102 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
1103 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
1104 col[n].rgbReserved = 0;
1108 SetDIBColorTable(This->hDC, 0, 256, col);
1111 /* This is to make LockRect read the gl Texture although memory is allocated */
1112 This->Flags |= SFLAG_NEWDC;
1114 This->Flags |= SFLAG_DIBSECTION;
1117 /* Lock the surface */
1118 hr = IWineD3DSurface_LockRect(iface,
1119 &lock,
1120 NULL,
1122 This->Flags &= ~SFLAG_NEWDC;
1123 if(FAILED(hr))
1125 ERR("IWineD3DSurface_LockRect failed with hr = %08lx\n", hr);
1126 /* keep the dib section */
1127 return hr;
1130 *pHDC = This->hDC;
1131 TRACE("returning %p\n",*pHDC);
1132 This->Flags |= SFLAG_DCINUSE;
1134 return WINED3D_OK;
1137 HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
1138 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1140 TRACE("(%p)->(%p)\n",This,hDC);
1142 if (!(This->Flags & SFLAG_DCINUSE))
1143 return D3DERR_INVALIDCALL;
1145 /* we locked first, so unlock now */
1146 IWineD3DSurface_UnlockRect(iface);
1148 This->Flags &= ~SFLAG_DCINUSE;
1150 return WINED3D_OK;
1153 /* ******************************************************
1154 IWineD3DSurface Internal (No mapping to directx api) parts follow
1155 ****************************************************** */
1156 HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface) {
1157 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1159 if (This->Flags & SFLAG_INTEXTURE) {
1160 TRACE("Surface already in texture\n");
1161 return WINED3D_OK;
1163 if (!(This->Flags & SFLAG_DIRTY)) {
1164 TRACE("surface isn't dirty\n");
1165 return WINED3D_OK;
1168 This->Flags &= ~SFLAG_DIRTY;
1170 /* Resources are placed in system RAM and do not need to be recreated when a device is lost.
1171 * These resources are not bound by device size or format restrictions. Because of this,
1172 * these resources cannot be accessed by the Direct3D device nor set as textures or render targets.
1173 * However, these resources can always be created, locked, and copied.
1174 * In general never store scratch or system mem textures in the video ram. However it is allowed
1175 * for system memory textures when WINED3DDEVCAPS_TEXTURESYSTEMMEMORY is set but it isn't right now.
1177 if (This->resource.pool == WINED3DPOOL_SCRATCH || This->resource.pool == WINED3DPOOL_SYSTEMMEM)
1179 FIXME("(%p) Operation not supported for scratch or SYSTEMMEM textures\n",This);
1180 return WINED3DERR_INVALIDCALL;
1183 if (This->Flags & SFLAG_INPBUFFER) {
1184 ENTER_GL();
1186 if (This->glDescription.level != 0)
1187 FIXME("Surface in texture is only supported for level 0\n");
1188 else if (This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8 ||
1189 This->resource.format == WINED3DFMT_DXT1 || This->resource.format == WINED3DFMT_DXT2 ||
1190 This->resource.format == WINED3DFMT_DXT3 || This->resource.format == WINED3DFMT_DXT4 ||
1191 This->resource.format == WINED3DFMT_DXT5)
1192 FIXME("Format %d not supported\n", This->resource.format);
1193 else {
1194 GLint prevRead;
1195 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1196 vcheckGLcall("glGetIntegerv");
1197 glReadBuffer(GL_BACK);
1198 vcheckGLcall("glReadBuffer");
1200 glCopyTexImage2D(This->glDescription.target,
1201 This->glDescription.level,
1202 This->glDescription.glFormatInternal,
1205 This->currentDesc.Width,
1206 This->currentDesc.Height,
1209 checkGLcall("glCopyTexImage2D");
1210 glReadBuffer(prevRead);
1211 vcheckGLcall("glReadBuffer");
1212 TRACE("Updating target %d\n", This->glDescription.target);
1213 This->Flags |= SFLAG_INTEXTURE;
1215 LEAVE_GL();
1216 return WINED3D_OK;
1219 if ((This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8) &&
1220 !GL_SUPPORT(EXT_PALETTED_TEXTURE)) {
1222 * wanted a paletted texture and not really support it in HW
1223 * so software emulation code begin
1225 UINT i;
1226 PALETTEENTRY* pal = This->resource.wineD3DDevice->palettes[This->resource.wineD3DDevice->currentPalette];
1227 VOID* surface = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->currentDesc.Width * This->currentDesc.Height * sizeof(DWORD));
1228 BYTE* dst = (BYTE*) surface;
1229 BYTE* src = (BYTE*) This->resource.allocatedMemory;
1231 for (i = 0; i < This->currentDesc.Width * This->currentDesc.Height; i++) {
1232 BYTE color = *src++;
1233 *dst++ = pal[color].peRed;
1234 *dst++ = pal[color].peGreen;
1235 *dst++ = pal[color].peBlue;
1236 if (This->resource.format == WINED3DFMT_A8P8)
1237 *dst++ = pal[color].peFlags;
1238 else
1239 *dst++ = 0xFF;
1242 ENTER_GL();
1244 TRACE("Calling glTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
1245 This->glDescription.target,
1246 This->glDescription.level,
1247 GL_RGBA,
1248 This->currentDesc.Width,
1249 This->currentDesc.Height,
1251 GL_RGBA,
1252 GL_UNSIGNED_BYTE,
1253 surface);
1254 glTexImage2D(This->glDescription.target,
1255 This->glDescription.level,
1256 GL_RGBA,
1257 This->currentDesc.Width,
1258 This->currentDesc.Height,
1260 GL_RGBA,
1261 GL_UNSIGNED_BYTE,
1262 surface);
1263 checkGLcall("glTexImage2D");
1264 HeapFree(GetProcessHeap(), 0, surface);
1266 LEAVE_GL();
1268 return WINED3D_OK;
1271 /* TODO: Compressed non-power 2 support */
1273 if (This->resource.format == WINED3DFMT_DXT1 ||
1274 This->resource.format == WINED3DFMT_DXT2 ||
1275 This->resource.format == WINED3DFMT_DXT3 ||
1276 This->resource.format == WINED3DFMT_DXT4 ||
1277 This->resource.format == WINED3DFMT_DXT5) {
1278 if (!GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
1279 FIXME("Using DXT1/3/5 without advertized support\n");
1280 } else if (This->resource.allocatedMemory) {
1281 TRACE("Calling glCompressedTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, sz=%d, Mem=%p\n",
1282 This->glDescription.target,
1283 This->glDescription.level,
1284 This->glDescription.glFormatInternal,
1285 This->currentDesc.Width,
1286 This->currentDesc.Height,
1288 This->resource.size,
1289 This->resource.allocatedMemory);
1291 ENTER_GL();
1293 GL_EXTCALL(glCompressedTexImage2DARB)(This->glDescription.target,
1294 This->glDescription.level,
1295 This->glDescription.glFormatInternal,
1296 This->currentDesc.Width,
1297 This->currentDesc.Height,
1299 This->resource.size,
1300 This->resource.allocatedMemory);
1301 checkGLcall("glCommpressedTexImage2D");
1303 LEAVE_GL();
1305 if(!(This->Flags & SFLAG_DONOTFREE)){
1306 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1307 This->resource.allocatedMemory = NULL;
1310 } else {
1312 /* TODO: possibly use texture rectangle (though we are probably more compatible without it) */
1313 if (NP2_REPACK == wined3d_settings.nonpower2_mode && (This->Flags & SFLAG_NONPOW2)) {
1316 TRACE("non power of two support\n");
1317 ENTER_GL();
1318 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,
1319 This->glDescription.target,
1320 This->glDescription.level,
1321 debug_d3dformat(This->resource.format),
1322 This->glDescription.glFormatInternal,
1323 This->pow2Width,
1324 This->pow2Height,
1326 This->glDescription.glFormat,
1327 This->glDescription.glType,
1328 NULL);
1330 glTexImage2D(This->glDescription.target,
1331 This->glDescription.level,
1332 This->glDescription.glFormatInternal,
1333 This->pow2Width,
1334 This->pow2Height,
1335 0/*border*/,
1336 This->glDescription.glFormat,
1337 This->glDescription.glType,
1338 NULL);
1340 checkGLcall("glTexImage2D");
1341 if (This->resource.allocatedMemory != NULL) {
1342 TRACE("(%p) Calling glTexSubImage2D w(%d) h(%d) mem(%p)\n", This, This->currentDesc.Width, This->currentDesc.Height, This->resource.allocatedMemory);
1343 /* And map the non-power two data into the top left corner */
1344 glTexSubImage2D(
1345 This->glDescription.target,
1346 This->glDescription.level,
1347 0 /* xoffset */,
1348 0 /* ysoffset */ ,
1349 This->currentDesc.Width,
1350 This->currentDesc.Height,
1351 This->glDescription.glFormat,
1352 This->glDescription.glType,
1353 This->resource.allocatedMemory
1355 checkGLcall("glTexSubImage2D");
1357 LEAVE_GL();
1359 } else {
1361 TRACE("Calling 2 glTexImage2D %x i=%d, d3dfmt=%s, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
1362 This->glDescription.target,
1363 This->glDescription.level,
1364 debug_d3dformat(This->resource.format),
1365 This->glDescription.glFormatInternal,
1366 This->pow2Width,
1367 This->pow2Height,
1369 This->glDescription.glFormat,
1370 This->glDescription.glType,
1371 This->resource.allocatedMemory);
1373 ENTER_GL();
1374 glTexImage2D(This->glDescription.target,
1375 This->glDescription.level,
1376 This->glDescription.glFormatInternal,
1377 This->pow2Width,
1378 This->pow2Height,
1379 0 /* border */,
1380 This->glDescription.glFormat,
1381 This->glDescription.glType,
1382 This->resource.allocatedMemory);
1383 checkGLcall("glTexImage2D");
1384 LEAVE_GL();
1387 #if 0
1389 static unsigned int gen = 0;
1390 char buffer[4096];
1391 ++gen;
1392 if ((gen % 10) == 0) {
1393 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
1394 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
1397 * debugging crash code
1398 if (gen == 250) {
1399 void** test = NULL;
1400 *test = 0;
1404 #endif
1405 if(!(This->Flags & SFLAG_DONOTFREE)){
1406 HeapFree(GetProcessHeap(),0,This->resource.allocatedMemory);
1407 This->resource.allocatedMemory = NULL;
1412 return WINED3D_OK;
1415 #include <errno.h>
1416 #include <stdio.h>
1417 HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename) {
1418 FILE* f = NULL;
1419 UINT i, y;
1420 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1421 char *allocatedMemory;
1422 char *textureRow;
1423 IWineD3DSwapChain *swapChain = NULL;
1424 int width, height;
1425 GLuint tmpTexture;
1426 DWORD color;
1427 /*FIXME:
1428 Textures my not be stored in ->allocatedgMemory and a GlTexture
1429 so we should lock the surface before saving a snapshot, or at least check that
1431 /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
1432 by calling GetTexImage and in compressed form by calling
1433 GetCompressedTexImageARB. Queried compressed images can be saved and
1434 later reused by calling CompressedTexImage[123]DARB. Pre-compressed
1435 texture images do not need to be processed by the GL and should
1436 significantly improve texture loading performance relative to uncompressed
1437 images. */
1439 /* Setup the width and height to be the internal texture width and height. */
1440 width = This->pow2Width;
1441 height = This->pow2Height;
1442 /* check to see if were a 'virtual' texture e.g. were not a pbuffer of texture were a back buffer*/
1443 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapChain);
1445 if (swapChain || (This->Flags & SFLAG_INPBUFFER)) { /* if were not a real texture then read the back buffer into a real texture*/
1446 /* 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 */
1447 GLint prevRead;
1448 ENTER_GL();
1449 FIXME("(%p) This surface needs to be locked before a snapshot can be taken\n", This);
1450 glEnable(GL_TEXTURE_2D);
1452 glGenTextures(1, &tmpTexture);
1453 glBindTexture(GL_TEXTURE_2D, tmpTexture);
1455 glTexImage2D(GL_TEXTURE_2D,
1457 GL_RGBA,
1458 width,
1459 height,
1460 0/*border*/,
1461 GL_RGBA,
1462 GL_UNSIGNED_INT_8_8_8_8_REV,
1463 NULL);
1465 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1466 vcheckGLcall("glGetIntegerv");
1467 glReadBuffer(GL_BACK);
1468 vcheckGLcall("glReadBuffer");
1469 glCopyTexImage2D(GL_TEXTURE_2D,
1471 GL_RGBA,
1474 width,
1475 height,
1478 checkGLcall("glCopyTexImage2D");
1479 glReadBuffer(prevRead);
1480 LEAVE_GL();
1482 } else { /* bind the real texture */
1483 IWineD3DSurface_PreLoad(iface);
1485 allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width * height * 4);
1486 ENTER_GL();
1487 FIXME("Saving texture level %d width %d height %d\n", This->glDescription.level, width, height);
1488 glGetTexImage(GL_TEXTURE_2D,
1489 This->glDescription.level,
1490 GL_RGBA,
1491 GL_UNSIGNED_INT_8_8_8_8_REV,
1492 allocatedMemory);
1493 checkGLcall("glTexImage2D");
1494 if (tmpTexture) {
1495 glBindTexture(GL_TEXTURE_2D, 0);
1496 glDeleteTextures(1, &tmpTexture);
1498 LEAVE_GL();
1500 f = fopen(filename, "w+");
1501 if (NULL == f) {
1502 ERR("opening of %s failed with: %s\n", filename, strerror(errno));
1503 return WINED3DERR_INVALIDCALL;
1505 /* Save the dat out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha chanel*/
1506 TRACE("(%p) opened %s with format %s\n", This, filename, debug_d3dformat(This->resource.format));
1507 /* TGA header */
1508 fputc(0,f);
1509 fputc(0,f);
1510 fputc(2,f);
1511 fputc(0,f);
1512 fputc(0,f);
1513 fputc(0,f);
1514 fputc(0,f);
1515 fputc(0,f);
1516 fputc(0,f);
1517 fputc(0,f);
1518 fputc(0,f);
1519 fputc(0,f);
1520 /* short width*/
1521 fwrite(&width,2,1,f);
1522 /* short height */
1523 fwrite(&height,2,1,f);
1524 /* format rgba */
1525 fputc(0x20,f);
1526 fputc(0x28,f);
1527 /* raw data */
1528 /* 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*/
1529 if(swapChain)
1530 textureRow = allocatedMemory + (width * (height - 1) *4);
1531 else
1532 textureRow = allocatedMemory;
1533 for (y = 0 ; y < height; y++) {
1534 for (i = 0; i < width; i++) {
1535 color = *((DWORD*)textureRow);
1536 fputc((color >> 16) & 0xFF, f); /* B */
1537 fputc((color >> 8) & 0xFF, f); /* G */
1538 fputc((color >> 0) & 0xFF, f); /* R */
1539 fputc((color >> 24) & 0xFF, f); /* A */
1540 textureRow += 4;
1542 /* take two rows of the pointer to the texture memory */
1543 if(swapChain)
1544 (textureRow-= width << 3);
1547 TRACE("Closing file\n");
1548 fclose(f);
1550 if(swapChain) {
1551 IWineD3DSwapChain_Release(swapChain);
1553 HeapFree(GetProcessHeap(), 0, allocatedMemory);
1554 return WINED3D_OK;
1557 HRESULT WINAPI IWineD3DSurfaceImpl_CleanDirtyRect(IWineD3DSurface *iface) {
1558 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1559 This->Flags &= ~SFLAG_DIRTY;
1560 This->dirtyRect.left = This->currentDesc.Width;
1561 This->dirtyRect.top = This->currentDesc.Height;
1562 This->dirtyRect.right = 0;
1563 This->dirtyRect.bottom = 0;
1564 TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Flags & SFLAG_DIRTY ? 1 : 0, This->dirtyRect.left,
1565 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
1566 return WINED3D_OK;
1570 * Slightly inefficient way to handle multiple dirty rects but it works :)
1572 extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) {
1573 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1574 IWineD3DBaseTexture *baseTexture = NULL;
1575 This->Flags |= SFLAG_DIRTY;
1576 if (NULL != pDirtyRect) {
1577 This->dirtyRect.left = min(This->dirtyRect.left, pDirtyRect->left);
1578 This->dirtyRect.top = min(This->dirtyRect.top, pDirtyRect->top);
1579 This->dirtyRect.right = max(This->dirtyRect.right, pDirtyRect->right);
1580 This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
1581 } else {
1582 This->dirtyRect.left = 0;
1583 This->dirtyRect.top = 0;
1584 This->dirtyRect.right = This->currentDesc.Width;
1585 This->dirtyRect.bottom = This->currentDesc.Height;
1587 TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Flags & SFLAG_DIRTY, This->dirtyRect.left,
1588 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
1589 /* if the container is a basetexture then mark it dirty. */
1590 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
1591 TRACE("Passing to conatiner\n");
1592 IWineD3DBaseTexture_SetDirty(baseTexture, TRUE);
1593 IWineD3DBaseTexture_Release(baseTexture);
1595 return WINED3D_OK;
1598 HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
1599 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1601 TRACE("This %p, container %p\n", This, container);
1603 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
1605 TRACE("Setting container to %p from %p\n", container, This->container);
1606 This->container = container;
1608 return WINED3D_OK;
1611 HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
1612 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1614 if (This->resource.format != WINED3DFMT_UNKNOWN) {
1615 FIXME("(%p) : The foramt of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
1616 return WINED3DERR_INVALIDCALL;
1619 TRACE("(%p) : Setting texture foramt to (%d,%s)\n", This, format, debug_d3dformat(format));
1620 if (format == WINED3DFMT_UNKNOWN) {
1621 This->resource.size = 0;
1622 } else if (format == WINED3DFMT_DXT1) {
1623 /* DXT1 is half byte per pixel */
1624 This->resource.size = ((max(This->pow2Width, 4) * D3DFmtGetBpp(This->resource.wineD3DDevice, format)) * max(This->pow2Height, 4)) >> 1;
1626 } else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
1627 format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) {
1628 This->resource.size = ((max(This->pow2Width, 4) * D3DFmtGetBpp(This->resource.wineD3DDevice, format)) * max(This->pow2Height, 4));
1629 } else {
1630 This->resource.size = (This->pow2Width * D3DFmtGetBpp(This->resource.wineD3DDevice, format)) * This->pow2Height;
1634 /* Setup some glformat defaults */
1635 if (format != WINED3DFMT_UNKNOWN) {
1636 This->glDescription.glFormat = D3DFmt2GLFmt(This->resource.wineD3DDevice, format);
1637 This->glDescription.glFormatInternal = D3DFmt2GLIntFmt(This->resource.wineD3DDevice, format);
1638 This->glDescription.glType = D3DFmt2GLType(This->resource.wineD3DDevice, format);
1639 } else {
1640 This->glDescription.glFormat = 0;
1641 This->glDescription.glFormatInternal = 0;
1642 This->glDescription.glType = 0;
1645 if (format != WINED3DFMT_UNKNOWN) {
1646 This->bytesPerPixel = D3DFmtGetBpp(This->resource.wineD3DDevice, format);
1647 This->pow2Size = (This->pow2Width * This->bytesPerPixel) * This->pow2Height;
1648 } else {
1649 This->bytesPerPixel = 0;
1650 This->pow2Size = 0;
1653 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
1655 This->resource.format = format;
1657 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);
1659 return WINED3D_OK;
1662 /* TODO: replace this function with context management routines */
1663 HRESULT WINAPI IWineD3DSurfaceImpl_SetPBufferState(IWineD3DSurface *iface, BOOL inPBuffer, BOOL inTexture) {
1664 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1666 if(inPBuffer) {
1667 This->Flags |= SFLAG_INPBUFFER;
1668 } else {
1669 This->Flags &= ~SFLAG_INPBUFFER;
1672 if(inTexture) {
1673 This->Flags |= SFLAG_INTEXTURE;
1674 } else {
1675 This->Flags &= ~SFLAG_INTEXTURE;
1678 return WINED3D_OK;
1681 HRESULT WINAPI IWineD3DSurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD Flags) {
1682 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1683 IWineD3DDevice *D3D = (IWineD3DDevice *) This->resource.wineD3DDevice;
1684 TRACE("(%p)->(%p,%lx)\n", This, override, Flags);
1686 /* Flipping is only supported on RenderTargets */
1687 if( !(This->resource.usage & WINED3DUSAGE_RENDERTARGET) ) return DDERR_NOTFLIPPABLE;
1689 if(override) {
1690 /* DDraw sets this for the X11 surfaces, so don't confuse the user
1691 * FIXME("(%p) Target override is not supported by now\n", This);
1692 * Additionally, it isn't really possible to support triple-buffering
1693 * properly on opengl at all
1697 /* Flipping a OpenGL surface -> Use WineD3DDevice::Present */
1698 return IWineD3DDevice_Present(D3D, NULL, NULL, 0, NULL);
1701 HRESULT WINAPI IWineD3DSurfaceImpl_Blt(IWineD3DSurface *iface, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
1702 FIXME("This is unimplemented for now(d3d7 merge)\n");
1703 return WINED3DERR_INVALIDCALL;
1706 HRESULT WINAPI IWineD3DSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags) {
1707 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1708 TRACE("(%p)->(%lx)\n", This, Flags);
1710 switch (Flags)
1712 case DDGBS_CANBLT:
1713 case DDGBS_ISBLTDONE:
1714 return DD_OK;
1716 default:
1717 return DDERR_INVALIDPARAMS;
1721 HRESULT WINAPI IWineD3DSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
1722 /* XXX: DDERR_INVALIDSURFACETYPE */
1724 TRACE("(%p)->(%08lx)\n",iface,Flags);
1725 switch (Flags) {
1726 case DDGFS_CANFLIP:
1727 case DDGFS_ISFLIPDONE:
1728 return DD_OK;
1730 default:
1731 return DDERR_INVALIDPARAMS;
1735 HRESULT WINAPI IWineD3DSurfaceImpl_IsLost(IWineD3DSurface *iface) {
1736 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1737 TRACE("(%p)\n", This);
1739 return This->Flags & SFLAG_LOST ? DDERR_SURFACELOST : WINED3D_OK;
1742 HRESULT WINAPI IWineD3DSurfaceImpl_Restore(IWineD3DSurface *iface) {
1743 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1744 TRACE("(%p)\n", This);
1746 /* So far we don't lose anything :) */
1747 This->Flags &= ~SFLAG_LOST;
1748 return WINED3D_OK;
1751 HRESULT WINAPI IWineD3DSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty, IWineD3DSurface *Source, RECT *rsrc, DWORD trans) {
1752 FIXME("This is unimplemented for now(d3d7 merge)\n");
1753 return WINED3DERR_INVALIDCALL;
1756 HRESULT WINAPI IWineD3DSurfaceImpl_SetPixelFormat(IWineD3DSurface *iface, WINED3DFORMAT Format, BYTE *Surface, DWORD Size) {
1757 FIXME("This is unimplemented for now(d3d7 merge)\n");
1758 return WINED3DERR_INVALIDCALL;
1761 HRESULT WINAPI IWineD3DSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
1762 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1763 TRACE("(%p)->(%p)\n", This, Pal);
1765 *Pal = (IWineD3DPalette *) This->palette;
1766 return DD_OK;
1769 HRESULT WINAPI IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface *iface) {
1770 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1771 RGBQUAD col[256];
1772 IWineD3DPaletteImpl *pal = This->palette;
1773 unsigned int n;
1774 TRACE("(%p)\n", This);
1776 if(This->resource.format == WINED3DFMT_P8 ||
1777 This->resource.format == WINED3DFMT_A8P8)
1779 TRACE("Dirtifying surface\n");
1780 This->Flags |= SFLAG_DIRTY;
1783 TRACE("(%p): Updating the palette\n", This);
1784 for (n=0; n<256; n++) {
1785 col[n].rgbRed = pal->palents[n].peRed;
1786 col[n].rgbGreen = pal->palents[n].peGreen;
1787 col[n].rgbBlue = pal->palents[n].peBlue;
1788 col[n].rgbReserved = 0;
1790 SetDIBColorTable(This->hDC, 0, 256, col);
1792 return WINED3D_OK;
1795 HRESULT WINAPI IWineD3DSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
1796 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1797 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
1798 TRACE("(%p)->(%p)\n", This, Pal);
1800 if(This->palette != NULL)
1801 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
1802 This->palette->Flags &= ~DDPCAPS_PRIMARYSURFACE;
1804 if(PalImpl != NULL) {
1805 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
1806 /* Set the device's main palette if the palette
1807 * wasn't a primary palette before
1809 if(!(PalImpl->Flags & DDPCAPS_PRIMARYSURFACE)) {
1810 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1811 unsigned int i;
1813 for(i=0; i < 256; i++) {
1814 device->palettes[device->currentPalette][i] = PalImpl->palents[i];
1818 (PalImpl)->Flags |= DDPCAPS_PRIMARYSURFACE;
1821 This->palette = PalImpl;
1823 return IWineD3DSurface_RealizePalette(iface);
1826 HRESULT WINAPI IWineD3DSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, DDCOLORKEY *CKey) {
1827 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1828 BOOL dirtify = FALSE;
1829 TRACE("(%p)->(%08lx,%p)\n", This, Flags, CKey);
1831 if ((Flags & DDCKEY_COLORSPACE) != 0) {
1832 FIXME(" colorkey value not supported (%08lx) !\n", Flags);
1833 return DDERR_INVALIDPARAMS;
1836 /* Dirtify the surface, but only if a key was changed */
1837 if(CKey) {
1838 switch (Flags & ~DDCKEY_COLORSPACE) {
1839 case DDCKEY_DESTBLT:
1840 if(!(This->CKeyFlags & DDSD_CKDESTBLT)) {
1841 dirtify = TRUE;
1842 } else {
1843 dirtify = memcmp(&This->DestBltCKey, CKey, sizeof(*CKey) ) != 0;
1845 This->DestBltCKey = *CKey;
1846 This->CKeyFlags |= DDSD_CKDESTBLT;
1847 break;
1849 case DDCKEY_DESTOVERLAY:
1850 if(!(This->CKeyFlags & DDSD_CKDESTOVERLAY)) {
1851 dirtify = TRUE;
1852 } else {
1853 dirtify = memcmp(&This->DestOverlayCKey, CKey, sizeof(*CKey)) != 0;
1855 This->DestOverlayCKey = *CKey;
1856 This->CKeyFlags |= DDSD_CKDESTOVERLAY;
1857 break;
1859 case DDCKEY_SRCOVERLAY:
1860 if(!(This->CKeyFlags & DDSD_CKSRCOVERLAY)) {
1861 dirtify = TRUE;
1862 } else {
1863 dirtify = memcmp(&This->SrcOverlayCKey, CKey, sizeof(*CKey)) != 0;
1865 This->SrcOverlayCKey = *CKey;
1866 This->CKeyFlags |= DDSD_CKSRCOVERLAY;
1867 break;
1869 case DDCKEY_SRCBLT:
1870 if(!(This->CKeyFlags & DDSD_CKSRCBLT)) {
1871 dirtify = TRUE;
1872 } else {
1873 dirtify = memcmp(&This->SrcBltCKey, CKey, sizeof(*CKey)) != 0;
1875 This->SrcBltCKey = *CKey;
1876 This->CKeyFlags |= DDSD_CKSRCBLT;
1877 break;
1880 else {
1881 switch (Flags & ~DDCKEY_COLORSPACE) {
1882 case DDCKEY_DESTBLT:
1883 dirtify = This->CKeyFlags & DDSD_CKDESTBLT;
1884 This->CKeyFlags &= ~DDSD_CKDESTBLT;
1885 break;
1887 case DDCKEY_DESTOVERLAY:
1888 dirtify = This->CKeyFlags & DDSD_CKDESTOVERLAY;
1889 This->CKeyFlags &= ~DDSD_CKDESTOVERLAY;
1890 break;
1892 case DDCKEY_SRCOVERLAY:
1893 dirtify = This->CKeyFlags & DDSD_CKSRCOVERLAY;
1894 This->CKeyFlags &= ~DDSD_CKSRCOVERLAY;
1895 break;
1897 case DDCKEY_SRCBLT:
1898 dirtify = This->CKeyFlags & DDSD_CKSRCBLT;
1899 This->CKeyFlags &= ~DDSD_CKSRCBLT;
1900 break;
1904 if(dirtify) {
1905 TRACE("Color key changed, dirtifing surface\n");
1906 This->Flags |= SFLAG_DIRTY;
1909 return WINED3D_OK;
1912 HRESULT WINAPI IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface *iface) {
1913 /* Nothing to do for now */
1914 return WINED3D_OK;
1917 DWORD WINAPI IWineD3DSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
1918 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1919 DWORD ret;
1920 TRACE("(%p)\n", This);
1922 /* DXTn formats don't have exact pitches as they are to the new row of blocks,
1923 where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5)
1924 ie pitch = (width/4) * bytes per block */
1925 if (This->resource.format == WINED3DFMT_DXT1) /* DXT1 is 8 bytes per block */
1926 ret = (This->currentDesc.Width >> 2) << 3;
1927 else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
1928 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) /* DXT2/3/4/5 is 16 bytes per block */
1929 ret = (This->currentDesc.Width >> 2) << 4;
1930 else {
1931 if (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
1932 /* Front and back buffers are always lockes/unlocked on currentDesc.Width */
1933 ret = This->bytesPerPixel * This->currentDesc.Width; /* Bytes / row */
1934 } else {
1935 ret = This->bytesPerPixel * This->pow2Width;
1938 TRACE("(%p) Returning %ld\n", This, ret);
1939 return ret;
1942 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
1944 /* IUnknown */
1945 IWineD3DSurfaceImpl_QueryInterface,
1946 IWineD3DSurfaceImpl_AddRef,
1947 IWineD3DSurfaceImpl_Release,
1948 /* IWineD3DResource */
1949 IWineD3DSurfaceImpl_GetParent,
1950 IWineD3DSurfaceImpl_GetDevice,
1951 IWineD3DSurfaceImpl_SetPrivateData,
1952 IWineD3DSurfaceImpl_GetPrivateData,
1953 IWineD3DSurfaceImpl_FreePrivateData,
1954 IWineD3DSurfaceImpl_SetPriority,
1955 IWineD3DSurfaceImpl_GetPriority,
1956 IWineD3DSurfaceImpl_PreLoad,
1957 IWineD3DSurfaceImpl_GetType,
1958 /* IWineD3DSurface */
1959 IWineD3DSurfaceImpl_GetContainerParent,
1960 IWineD3DSurfaceImpl_GetContainer,
1961 IWineD3DSurfaceImpl_GetDesc,
1962 IWineD3DSurfaceImpl_LockRect,
1963 IWineD3DSurfaceImpl_UnlockRect,
1964 IWineD3DSurfaceImpl_GetDC,
1965 IWineD3DSurfaceImpl_ReleaseDC,
1966 IWineD3DSurfaceImpl_Flip,
1967 IWineD3DSurfaceImpl_Blt,
1968 IWineD3DSurfaceImpl_GetBltStatus,
1969 IWineD3DSurfaceImpl_GetFlipStatus,
1970 IWineD3DSurfaceImpl_IsLost,
1971 IWineD3DSurfaceImpl_Restore,
1972 IWineD3DSurfaceImpl_BltFast,
1973 IWineD3DSurfaceImpl_SetPixelFormat,
1974 IWineD3DSurfaceImpl_GetPalette,
1975 IWineD3DSurfaceImpl_SetPalette,
1976 IWineD3DSurfaceImpl_RealizePalette,
1977 IWineD3DSurfaceImpl_SetColorKey,
1978 IWineD3DSurfaceImpl_GetPitch,
1979 /* Internal use: */
1980 IWineD3DSurfaceImpl_CleanDirtyRect,
1981 IWineD3DSurfaceImpl_AddDirtyRect,
1982 IWineD3DSurfaceImpl_LoadTexture,
1983 IWineD3DSurfaceImpl_SaveSnapshot,
1984 IWineD3DSurfaceImpl_SetContainer,
1985 IWineD3DSurfaceImpl_SetPBufferState,
1986 IWineD3DSurfaceImpl_SetGlTextureDesc,
1987 IWineD3DSurfaceImpl_GetGlDesc,
1988 IWineD3DSurfaceImpl_GetData,
1989 IWineD3DSurfaceImpl_SetFormat,
1990 IWineD3DSurfaceImpl_PrivateSetup