static ULONG WINAPI IWineD3DTextureImpl_Release(IWineD3DTexture *iface) { IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface; ULONG ref; TRACE("(%p) : Releasing from %ld\n", This, This->resource.ref); ref = InterlockedDecrement(&This->resource.ref); if (ref == 0) { int i; TRACE("(%p) : Cleaning up\n",This); for (i = 0; i < This->baseTexture.levels; i++) { if (This->surfaces[i] != NULL) { /* Because the surfaces were created using a callback we need to release there parent otehrwise we leave the parent hanging */ IUnknown* surfaceParent; /* Clean out the texture name we gave to the suface so that the surface doesn't try and release it */ IWineD3DSurface_SetGlTextureDesc(This->surfaces[i], 0, 0); /* Cleanup the container */ IWineD3DSurface_SetContainer(This->surfaces[i], 0); /* Now, release the parent, which will take care of cleaning up the surface for us */ IWineD3DSurface_GetParent(This->surfaces[i], &surfaceParent); IUnknown_Release(surfaceParent); IUnknown_Release(surfaceParent); } } TRACE("(%p) : cleaning up base texture\n", This); IWineD3DBaseTextureImpl_CleanUp((IWineD3DBaseTexture *)iface); /* free the object */ HeapFree(GetProcessHeap(), 0, This); } return ref; }
static void texture_cleanup(IWineD3DTextureImpl *This) { unsigned int i; TRACE("(%p) : Cleaning up\n", This); for (i = 0; i < This->baseTexture.levels; ++i) { if (This->surfaces[i]) { /* Clean out the texture name we gave to the surface so that the * surface doesn't try and release it */ surface_set_texture_name(This->surfaces[i], 0, TRUE); surface_set_texture_name(This->surfaces[i], 0, FALSE); surface_set_texture_target(This->surfaces[i], 0); IWineD3DSurface_SetContainer(This->surfaces[i], 0); IWineD3DSurface_Release(This->surfaces[i]); } } TRACE("(%p) : Cleaning up base texture\n", This); basetexture_cleanup((IWineD3DBaseTexture *)This); }
static void texture_cleanup(IWineD3DTextureImpl *This) { unsigned int i; TRACE("(%p) : Cleaning up\n", This); for (i = 0; i < This->baseTexture.level_count; ++i) { IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)This->baseTexture.sub_resources[i]; if (surface) { /* Clean out the texture name we gave to the surface so that the * surface doesn't try and release it */ surface_set_texture_name(surface, 0, TRUE); surface_set_texture_name(surface, 0, FALSE); surface_set_texture_target(surface, 0); IWineD3DSurface_SetContainer((IWineD3DSurface *)surface, NULL); IWineD3DSurface_Release((IWineD3DSurface *)surface); } } TRACE("(%p) : Cleaning up base texture\n", This); basetexture_cleanup((IWineD3DBaseTexture *)This); }
HRESULT swapchain_init(IWineD3DSwapChainImpl *swapchain, WINED3DSURFTYPE surface_type, IWineD3DDeviceImpl *device, WINED3DPRESENT_PARAMETERS *present_parameters, IUnknown *parent) { const struct wined3d_adapter *adapter = device->adapter; const struct wined3d_format_desc *format_desc; BOOL displaymode_set = FALSE; WINED3DDISPLAYMODE mode; RECT client_rect; HWND window = NULL; #ifdef VBOX_WITH_WDDM IWineD3DSwapChainImpl *overridenSwapchain = NULL; HDC hDC = NULL; #endif HRESULT hr; UINT i; if (present_parameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) { ERR("The application requested %u back buffers, this is not supported.\n", present_parameters->BackBufferCount); return WINED3DERR_INVALIDCALL; } if (present_parameters->BackBufferCount > 1) { FIXME("The application requested more than one back buffer, this is not properly supported.\n" "Please configure the application to use double buffering (1 back buffer) if possible.\n"); } switch (surface_type) { case SURFACE_GDI: swapchain->lpVtbl = &IWineGDISwapChain_Vtbl; break; case SURFACE_OPENGL: swapchain->lpVtbl = &IWineD3DSwapChain_Vtbl; break; case SURFACE_UNKNOWN: FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain.\n"); return WINED3DERR_INVALIDCALL; } #ifdef VBOX_WITH_WDDM if (present_parameters->hDeviceWindow) { overridenSwapchain = swapchain_find(device, present_parameters->hDeviceWindow); if (!overridenSwapchain) { ERR("invalid window handle supplied"); return E_FAIL; } window = overridenSwapchain->win_handle; hDC = overridenSwapchain->hDC; } else { hr = VBoxExtWndCreate(present_parameters->BackBufferWidth, present_parameters->BackBufferHeight, &window, &hDC); if (FAILED(hr)) { ERR("VBoxExtWndCreate failed, hr 0x%x", hr); return hr; } } Assert(window); Assert(hDC); present_parameters->hDeviceWindow = window; #else window = present_parameters->hDeviceWindow ? present_parameters->hDeviceWindow : device->createParms.hFocusWindow; #endif swapchain->device = device; swapchain->parent = parent; swapchain->ref = 1; swapchain->win_handle = window; #ifndef VBOX_WITH_WDDM swapchain->device_window = window; #else Assert(window); swapchain->hDC = hDC; swapchain->presentRt = NULL; #endif if (!present_parameters->Windowed && window) { swapchain_setup_fullscreen_window(swapchain, present_parameters->BackBufferWidth, present_parameters->BackBufferHeight); } IWineD3D_GetAdapterDisplayMode(device->wined3d, adapter->ordinal, &mode); swapchain->orig_width = mode.Width; swapchain->orig_height = mode.Height; swapchain->orig_fmt = mode.Format; format_desc = getFormatDescEntry(mode.Format, &adapter->gl_info); #ifndef VBOX_WITH_WDDM GetClientRect(window, &client_rect); #else client_rect.left = 0; client_rect.top = 0; client_rect.right = present_parameters->BackBufferWidth; client_rect.bottom = present_parameters->BackBufferHeight; #endif if (present_parameters->Windowed && (!present_parameters->BackBufferWidth || !present_parameters->BackBufferHeight || present_parameters->BackBufferFormat == WINED3DFMT_UNKNOWN)) { if (!present_parameters->BackBufferWidth) { present_parameters->BackBufferWidth = client_rect.right; TRACE("Updating width to %u.\n", present_parameters->BackBufferWidth); } if (!present_parameters->BackBufferHeight) { present_parameters->BackBufferHeight = client_rect.bottom; TRACE("Updating height to %u.\n", present_parameters->BackBufferHeight); } if (present_parameters->BackBufferFormat == WINED3DFMT_UNKNOWN) { present_parameters->BackBufferFormat = swapchain->orig_fmt; TRACE("Updating format to %s.\n", debug_d3dformat(swapchain->orig_fmt)); } } swapchain->presentParms = *present_parameters; if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && present_parameters->BackBufferCount && (present_parameters->BackBufferWidth != client_rect.right || present_parameters->BackBufferHeight != client_rect.bottom)) { TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u.\n", present_parameters->BackBufferWidth, present_parameters->BackBufferHeight, client_rect.right, client_rect.bottom); swapchain->render_to_fbo = TRUE; } TRACE("Creating front buffer.\n"); hr = IWineD3DDeviceParent_CreateRenderTarget(device->device_parent, parent, swapchain->presentParms.BackBufferWidth, swapchain->presentParms.BackBufferHeight, swapchain->presentParms.BackBufferFormat, swapchain->presentParms.MultiSampleType, swapchain->presentParms.MultiSampleQuality, TRUE /* Lockable */, &swapchain->frontBuffer); if (FAILED(hr)) { WARN("Failed to create front buffer, hr %#x.\n", hr); goto err; } IWineD3DSurface_SetContainer(swapchain->frontBuffer, (IWineD3DBase *)swapchain); ((IWineD3DSurfaceImpl *)swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN; if (surface_type == SURFACE_OPENGL) { IWineD3DSurface_ModifyLocation(swapchain->frontBuffer, SFLAG_INDRAWABLE, TRUE); } /* MSDN says we're only allowed a single fullscreen swapchain per device, * so we should really check to see if there is a fullscreen swapchain * already. Does a single head count as full screen? */ if (!present_parameters->Windowed) { WINED3DDISPLAYMODE mode; /* Change the display settings */ mode.Width = present_parameters->BackBufferWidth; mode.Height = present_parameters->BackBufferHeight; mode.Format = present_parameters->BackBufferFormat; mode.RefreshRate = present_parameters->FullScreen_RefreshRateInHz; hr = IWineD3DDevice_SetDisplayMode((IWineD3DDevice *)device, 0, &mode); if (FAILED(hr)) { WARN("Failed to set display mode, hr %#x.\n", hr); goto err; } displaymode_set = TRUE; } #ifndef VBOX_WITH_WDDM swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(swapchain->context)); if (!swapchain->context) { ERR("Failed to create the context array.\n"); hr = E_OUTOFMEMORY; goto err; } swapchain->num_contexts = 1; #endif if (surface_type == SURFACE_OPENGL) { #ifdef VBOX_WITH_WDDM struct wined3d_context * swapchainContext; #endif const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; /* In WGL both color, depth and stencil are features of a pixel format. In case of D3D they are separate. * You are able to add a depth + stencil surface at a later stage when you need it. * In order to support this properly in WineD3D we need the ability to recreate the opengl context and * drawable when this is required. This is very tricky as we need to reapply ALL opengl states for the new * context, need torecreate shaders, textures and other resources. * * The context manager already takes care of the state problem and for the other tasks code from Reset * can be used. These changes are way to risky during the 1.0 code freeze which is taking place right now. * Likely a lot of other new bugs will be exposed. For that reason request a depth stencil surface all the * time. It can cause a slight performance hit but fixes a lot of regressions. A fixme reminds of that this * issue needs to be fixed. */ if (!present_parameters->EnableAutoDepthStencil || swapchain->presentParms.AutoDepthStencilFormat != WINED3DFMT_D24_UNORM_S8_UINT) { FIXME("Add OpenGL context recreation support to context_validate_onscreen_formats\n"); } swapchain->ds_format = getFormatDescEntry(WINED3DFMT_D24_UNORM_S8_UINT, gl_info); #ifdef VBOX_WITH_WDDM swapchainContext = context_find_create(device, swapchain, (IWineD3DSurfaceImpl *)swapchain->frontBuffer, swapchain->ds_format); if (!swapchainContext) #else swapchain->context[0] = context_create(swapchain, (IWineD3DSurfaceImpl *)swapchain->frontBuffer, swapchain->ds_format); if (!swapchain->context[0]) #endif { WARN("Failed to create context.\n"); hr = WINED3DERR_NOTAVAILABLE; goto err; } #ifdef VBOX_WITH_WDDM context_release(swapchainContext); #else context_release(swapchain->context[0]); #endif } else { #ifndef VBOX_WITH_WDDM swapchain->context[0] = NULL; #endif } if (swapchain->presentParms.BackBufferCount > 0) { swapchain->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->backBuffer) * swapchain->presentParms.BackBufferCount); if (!swapchain->backBuffer) { ERR("Failed to allocate backbuffer array memory.\n"); hr = E_OUTOFMEMORY; goto err; } for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i) { TRACE("Creating back buffer %u.\n", i); hr = IWineD3DDeviceParent_CreateRenderTarget(device->device_parent, parent, swapchain->presentParms.BackBufferWidth, swapchain->presentParms.BackBufferHeight, swapchain->presentParms.BackBufferFormat, swapchain->presentParms.MultiSampleType, swapchain->presentParms.MultiSampleQuality, TRUE /* Lockable */, &swapchain->backBuffer[i]); if (FAILED(hr)) { WARN("Failed to create back buffer %u, hr %#x.\n", i, hr); goto err; } IWineD3DSurface_SetContainer(swapchain->backBuffer[i], (IWineD3DBase *)swapchain); ((IWineD3DSurfaceImpl *)swapchain->backBuffer[i])->Flags |= SFLAG_SWAPCHAIN; } } /* Swapchains share the depth/stencil buffer, so only create a single depthstencil surface. */ if (present_parameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) { TRACE("Creating depth/stencil buffer.\n"); if (!device->auto_depth_stencil_buffer) { hr = IWineD3DDeviceParent_CreateDepthStencilSurface(device->device_parent, parent, swapchain->presentParms.BackBufferWidth, swapchain->presentParms.BackBufferHeight, swapchain->presentParms.AutoDepthStencilFormat, swapchain->presentParms.MultiSampleType, swapchain->presentParms.MultiSampleQuality, FALSE /* FIXME: Discard */, &device->auto_depth_stencil_buffer); if (FAILED(hr)) { WARN("Failed to create the auto depth stencil, hr %#x.\n", hr); goto err; } IWineD3DSurface_SetContainer(device->auto_depth_stencil_buffer, NULL); } } IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *)swapchain, &swapchain->orig_gamma); #ifdef VBOX_WITH_WDDM if (overridenSwapchain) { swapchain_invalidate(overridenSwapchain); } #endif return WINED3D_OK; err: if (displaymode_set) { DEVMODEW devmode; ClipCursor(NULL); /* Change the display settings */ memset(&devmode, 0, sizeof(devmode)); devmode.dmSize = sizeof(devmode); devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; devmode.dmBitsPerPel = format_desc->byte_count * 8; devmode.dmPelsWidth = swapchain->orig_width; devmode.dmPelsHeight = swapchain->orig_height; ChangeDisplaySettingsExW(adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL); } if (swapchain->backBuffer) { for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i) { if (swapchain->backBuffer[i]) IWineD3DSurface_Release(swapchain->backBuffer[i]); } HeapFree(GetProcessHeap(), 0, swapchain->backBuffer); } #ifdef VBOX_WITH_WDDM if (!device->NumberOfSwapChains) { while (device->numContexts) { context_destroy(device, device->contexts[0]); } } #else if (swapchain->context) { if (swapchain->context[0]) { context_release(swapchain->context[0]); context_destroy(device, swapchain->context[0]); swapchain->num_contexts = 0; } HeapFree(GetProcessHeap(), 0, swapchain->context); } #endif if (swapchain->frontBuffer) IWineD3DSurface_Release(swapchain->frontBuffer); #ifdef VBOX_WITH_WDDM if (!overridenSwapchain && swapchain->win_handle) { VBoxExtWndDestroy(swapchain->win_handle, swapchain->hDC); } swapchain_invalidate(swapchain); #endif return hr; }
/*IWineD3DSwapChain parts follow: */ static void WINAPI IWineD3DSwapChainImpl_Destroy(IWineD3DSwapChain *iface) { IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface; WINED3DDISPLAYMODE mode; unsigned int i; TRACE("Destroying swapchain %p\n", iface); IWineD3DSwapChain_SetGammaRamp(iface, 0, &This->orig_gamma); /* Release the swapchain's draw buffers. Make sure This->backBuffer[0] is * the last buffer to be destroyed, FindContext() depends on that. */ if (This->frontBuffer) { IWineD3DSurface_SetContainer(This->frontBuffer, 0); if (IWineD3DSurface_Release(This->frontBuffer)) { WARN("(%p) Something's still holding the front buffer (%p).\n", This, This->frontBuffer); } This->frontBuffer = NULL; } if (This->backBuffer) { i = This->presentParms.BackBufferCount; while (i--) { IWineD3DSurface_SetContainer(This->backBuffer[i], 0); if (IWineD3DSurface_Release(This->backBuffer[i])) WARN("(%p) Something's still holding back buffer %u (%p).\n", This, i, This->backBuffer[i]); } HeapFree(GetProcessHeap(), 0, This->backBuffer); This->backBuffer = NULL; } #ifndef VBOX_WINE_WITH_SINGLE_CONTEXT for (i = 0; i < This->num_contexts; ++i) { context_destroy(This->device, This->context[i]); } #endif #ifdef VBOX_WITH_WDDM if (This->presentRt) { IWineD3DSurfaceImpl *old = (IWineD3DSurfaceImpl*)This->presentRt; old->presentSwapchain = NULL; IWineD3DSurface_Release(This->presentRt); This->presentRt = NULL; } #endif IWineD3DDevice_RemoveSwapChain((IWineD3DDevice*)This->device, (IWineD3DSwapChain*)This); if (!This->device->NumberOfSwapChains) { /* Restore the screen resolution if we rendered in fullscreen * This will restore the screen resolution to what it was before creating the swapchain. In case of d3d8 and d3d9 * this will be the original desktop resolution. In case of d3d7 this will be a NOP because ddraw sets the resolution * before starting up Direct3D, thus orig_width and orig_height will be equal to the modes in the presentation params */ if(This->presentParms.Windowed == FALSE && This->presentParms.AutoRestoreDisplayMode) { mode.Width = This->orig_width; mode.Height = This->orig_height; mode.RefreshRate = 0; mode.Format = This->orig_fmt; IWineD3DDevice_SetDisplayMode((IWineD3DDevice *)This->device, 0, &mode); } } #ifdef VBOX_WITH_WDDM if(This->win_handle) { VBoxExtWndDestroy(This->win_handle, This->hDC); swapchain_invalidate(This); } else { WARN("null win info"); } #else HeapFree(GetProcessHeap(), 0, This->context); #endif HeapFree(GetProcessHeap(), 0, This); }
HRESULT texture_init(IWineD3DTextureImpl *texture, UINT width, UINT height, UINT levels, IWineD3DDeviceImpl *device, DWORD usage, WINED3DFORMAT format, WINED3DPOOL pool, IUnknown *parent, const struct wined3d_parent_ops *parent_ops #ifdef VBOX_WITH_WDDM , HANDLE *shared_handle , void **pavClientMem #endif ) { const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; const struct wined3d_format_desc *format_desc = getFormatDescEntry(format, gl_info); UINT pow2_width, pow2_height; UINT tmp_w, tmp_h; unsigned int i; HRESULT hr; /* TODO: It should only be possible to create textures for formats * that are reported as supported. */ if (WINED3DFMT_UNKNOWN >= format) { WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN.\n", texture); return WINED3DERR_INVALIDCALL; } /* Non-power2 support. */ if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO]) { pow2_width = width; pow2_height = height; } else { /* Find the nearest pow2 match. */ pow2_width = pow2_height = 1; while (pow2_width < width) pow2_width <<= 1; while (pow2_height < height) pow2_height <<= 1; if (pow2_width != width || pow2_height != height) { if (levels > 1) { WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support.\n"); return WINED3DERR_INVALIDCALL; } levels = 1; } } /* Calculate levels for mip mapping. */ if (usage & WINED3DUSAGE_AUTOGENMIPMAP) { if (!gl_info->supported[SGIS_GENERATE_MIPMAP]) { WARN("No mipmap generation support, returning WINED3DERR_INVALIDCALL.\n"); return WINED3DERR_INVALIDCALL; } if (levels > 1) { WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning WINED3DERR_INVALIDCALL.\n"); return WINED3DERR_INVALIDCALL; } levels = 1; } else if (!levels) { levels = wined3d_log2i(max(width, height)) + 1; TRACE("Calculated levels = %u.\n", levels); } texture->lpVtbl = &IWineD3DTexture_Vtbl; hr = basetexture_init((IWineD3DBaseTextureImpl *)texture, levels, WINED3DRTYPE_TEXTURE, device, 0, usage, format_desc, pool, parent, parent_ops #ifdef VBOX_WITH_WDDM , shared_handle, pavClientMem #endif ); if (FAILED(hr)) { WARN("Failed to initialize basetexture, returning %#x.\n", hr); return hr; } /* Precalculated scaling for 'faked' non power of two texture coords. * Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE * is used in combination with texture uploads (RTL_READTEX). The reason is that EXT_PALETTED_TEXTURE * doesn't work in combination with ARB_TEXTURE_RECTANGLE. */ if (gl_info->supported[WINE_NORMALIZED_TEXRECT] && (width != pow2_width || height != pow2_height)) { texture->baseTexture.pow2Matrix[0] = 1.0f; texture->baseTexture.pow2Matrix[5] = 1.0f; texture->baseTexture.pow2Matrix[10] = 1.0f; texture->baseTexture.pow2Matrix[15] = 1.0f; texture->target = GL_TEXTURE_2D; texture->cond_np2 = TRUE; texture->baseTexture.minMipLookup = minMipLookup_noFilter; } else if (gl_info->supported[ARB_TEXTURE_RECTANGLE] && (width != pow2_width || height != pow2_height) && !(format_desc->format == WINED3DFMT_P8_UINT && gl_info->supported[EXT_PALETTED_TEXTURE] && wined3d_settings.rendertargetlock_mode == RTL_READTEX)) { if ((width != 1) || (height != 1)) texture->baseTexture.pow2Matrix_identity = FALSE; texture->baseTexture.pow2Matrix[0] = (float)width; texture->baseTexture.pow2Matrix[5] = (float)height; texture->baseTexture.pow2Matrix[10] = 1.0f; texture->baseTexture.pow2Matrix[15] = 1.0f; texture->target = GL_TEXTURE_RECTANGLE_ARB; texture->cond_np2 = TRUE; if(texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) { texture->baseTexture.minMipLookup = minMipLookup_noMip; } else { texture->baseTexture.minMipLookup = minMipLookup_noFilter; } } else { if ((width != pow2_width) || (height != pow2_height)) { texture->baseTexture.pow2Matrix_identity = FALSE; texture->baseTexture.pow2Matrix[0] = (((float)width) / ((float)pow2_width)); texture->baseTexture.pow2Matrix[5] = (((float)height) / ((float)pow2_height)); } else { texture->baseTexture.pow2Matrix[0] = 1.0f; texture->baseTexture.pow2Matrix[5] = 1.0f; } texture->baseTexture.pow2Matrix[10] = 1.0f; texture->baseTexture.pow2Matrix[15] = 1.0f; texture->target = GL_TEXTURE_2D; texture->cond_np2 = FALSE; } TRACE("xf(%f) yf(%f)\n", texture->baseTexture.pow2Matrix[0], texture->baseTexture.pow2Matrix[5]); /* Generate all the surfaces. */ tmp_w = width; tmp_h = height; for (i = 0; i < texture->baseTexture.levels; ++i) { #ifdef VBOX_WITH_WDDM /* Use the callback to create the texture surface. */ hr = IWineD3DDeviceParent_CreateSurface(device->device_parent, parent, tmp_w, tmp_h, format_desc->format, usage, pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &texture->surfaces[i] , NULL /* <- we first create a surface in an everage "non-shared" fashion and initialize its share properties later (see below) * this is done this way because the surface does not have its parent (texture) setup properly * thus we can not initialize texture at this stage */ , pavClientMem ? pavClientMem[i] : NULL); #else /* Use the callback to create the texture surface. */ hr = IWineD3DDeviceParent_CreateSurface(device->device_parent, parent, tmp_w, tmp_h, format_desc->format, usage, pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &texture->surfaces[i]); #endif if (FAILED(hr)) { FIXME("Failed to create surface %p, hr %#x\n", texture, hr); texture->surfaces[i] = NULL; texture_cleanup(texture); return hr; } IWineD3DSurface_SetContainer(texture->surfaces[i], (IWineD3DBase *)texture); TRACE("Created surface level %u @ %p.\n", i, texture->surfaces[i]); surface_set_texture_target(texture->surfaces[i], texture->target); /* Calculate the next mipmap level. */ tmp_w = max(1, tmp_w >> 1); tmp_h = max(1, tmp_h >> 1); } texture->baseTexture.internal_preload = texture_internal_preload; #ifdef VBOX_WITH_WDDM if (VBOXSHRC_IS_SHARED(texture)) { Assert(shared_handle); for (i = 0; i < texture->baseTexture.levels; ++i) { VBOXSHRC_COPY_SHAREDATA((IWineD3DSurfaceImpl*)texture->surfaces[i], texture); } #ifdef DEBUG for (i = 0; i < texture->baseTexture.levels; ++i) { Assert(!((IWineD3DSurfaceImpl*)texture->surfaces[i])->texture_name); } #endif for (i = 0; i < texture->baseTexture.levels; ++i) { if (!VBOXSHRC_IS_SHARED_OPENED(texture)) { IWineD3DSurface_LoadLocation(texture->surfaces[i], SFLAG_INTEXTURE, NULL); Assert(!(*shared_handle)); *shared_handle = VBOXSHRC_GET_SHAREHANDLE(texture); } else { surface_setup_location_onopen((IWineD3DSurfaceImpl*)texture->surfaces[i]); Assert(*shared_handle); Assert(*shared_handle == VBOXSHRC_GET_SHAREHANDLE(texture)); } } #ifdef DEBUG for (i = 0; i < texture->baseTexture.levels; ++i) { Assert((GLuint)(*shared_handle) == ((IWineD3DSurfaceImpl*)texture->surfaces[i])->texture_name); } #endif if (!VBOXSHRC_IS_SHARED_OPENED(texture)) { struct wined3d_context * context; Assert(!device->isInDraw); /* flush to ensure the texture is allocated before it is used by another * process opening it */ context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD); if (context->valid) { wglFlush(); } else { ERR("invalid context!"); } context_release(context); } } else { Assert(!shared_handle); } #endif return WINED3D_OK; }
HRESULT texture_init(IWineD3DTextureImpl *texture, UINT width, UINT height, UINT levels, IWineD3DDeviceImpl *device, DWORD usage, WINED3DFORMAT format, WINED3DPOOL pool, IUnknown *parent, const struct wined3d_parent_ops *parent_ops) { const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; const struct wined3d_format_desc *format_desc = getFormatDescEntry(format, gl_info); UINT pow2_width, pow2_height; UINT tmp_w, tmp_h; unsigned int i; HRESULT hr; /* TODO: It should only be possible to create textures for formats * that are reported as supported. */ if (WINED3DFMT_UNKNOWN >= format) { WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN.\n", texture); return WINED3DERR_INVALIDCALL; } /* Non-power2 support. */ if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO]) { pow2_width = width; pow2_height = height; } else { /* Find the nearest pow2 match. */ pow2_width = pow2_height = 1; while (pow2_width < width) pow2_width <<= 1; while (pow2_height < height) pow2_height <<= 1; if (pow2_width != width || pow2_height != height) { if (levels > 1) { WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support.\n"); return WINED3DERR_INVALIDCALL; } levels = 1; } } /* Calculate levels for mip mapping. */ if (usage & WINED3DUSAGE_AUTOGENMIPMAP) { if (!gl_info->supported[SGIS_GENERATE_MIPMAP]) { WARN("No mipmap generation support, returning WINED3DERR_INVALIDCALL.\n"); return WINED3DERR_INVALIDCALL; } if (levels > 1) { WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning WINED3DERR_INVALIDCALL.\n"); return WINED3DERR_INVALIDCALL; } levels = 1; } else if (!levels) { levels = wined3d_log2i(max(width, height)) + 1; TRACE("Calculated levels = %u.\n", levels); } texture->lpVtbl = &IWineD3DTexture_Vtbl; hr = basetexture_init((IWineD3DBaseTextureImpl *)texture, 1, levels, WINED3DRTYPE_TEXTURE, device, 0, usage, format_desc, pool, parent, parent_ops); if (FAILED(hr)) { WARN("Failed to initialize basetexture, returning %#x.\n", hr); return hr; } /* Precalculated scaling for 'faked' non power of two texture coords. * Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE * is used in combination with texture uploads (RTL_READTEX). The reason is that EXT_PALETTED_TEXTURE * doesn't work in combination with ARB_TEXTURE_RECTANGLE. */ if (gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT] && (width != pow2_width || height != pow2_height)) { texture->baseTexture.pow2Matrix[0] = 1.0f; texture->baseTexture.pow2Matrix[5] = 1.0f; texture->baseTexture.pow2Matrix[10] = 1.0f; texture->baseTexture.pow2Matrix[15] = 1.0f; texture->target = GL_TEXTURE_2D; texture->cond_np2 = TRUE; texture->baseTexture.minMipLookup = minMipLookup_noFilter; } else if (gl_info->supported[ARB_TEXTURE_RECTANGLE] && (width != pow2_width || height != pow2_height) && !(format_desc->format == WINED3DFMT_P8_UINT && gl_info->supported[EXT_PALETTED_TEXTURE] && wined3d_settings.rendertargetlock_mode == RTL_READTEX)) { if ((width != 1) || (height != 1)) texture->baseTexture.pow2Matrix_identity = FALSE; texture->baseTexture.pow2Matrix[0] = (float)width; texture->baseTexture.pow2Matrix[5] = (float)height; texture->baseTexture.pow2Matrix[10] = 1.0f; texture->baseTexture.pow2Matrix[15] = 1.0f; texture->target = GL_TEXTURE_RECTANGLE_ARB; texture->cond_np2 = TRUE; if(texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) { texture->baseTexture.minMipLookup = minMipLookup_noMip; } else { texture->baseTexture.minMipLookup = minMipLookup_noFilter; } } else { if ((width != pow2_width) || (height != pow2_height)) { texture->baseTexture.pow2Matrix_identity = FALSE; texture->baseTexture.pow2Matrix[0] = (((float)width) / ((float)pow2_width)); texture->baseTexture.pow2Matrix[5] = (((float)height) / ((float)pow2_height)); } else { texture->baseTexture.pow2Matrix[0] = 1.0f; texture->baseTexture.pow2Matrix[5] = 1.0f; } texture->baseTexture.pow2Matrix[10] = 1.0f; texture->baseTexture.pow2Matrix[15] = 1.0f; texture->target = GL_TEXTURE_2D; texture->cond_np2 = FALSE; } TRACE("xf(%f) yf(%f)\n", texture->baseTexture.pow2Matrix[0], texture->baseTexture.pow2Matrix[5]); /* Generate all the surfaces. */ tmp_w = width; tmp_h = height; for (i = 0; i < texture->baseTexture.level_count; ++i) { IWineD3DSurface *surface; /* Use the callback to create the texture surface. */ hr = IWineD3DDeviceParent_CreateSurface(device->device_parent, parent, tmp_w, tmp_h, format_desc->format, usage, pool, i, 0, &surface); if (FAILED(hr)) { FIXME("Failed to create surface %p, hr %#x\n", texture, hr); texture_cleanup(texture); return hr; } IWineD3DSurface_SetContainer(surface, (IWineD3DBase *)texture); surface_set_texture_target((IWineD3DSurfaceImpl *)surface, texture->target); texture->baseTexture.sub_resources[i] = (IWineD3DResourceImpl *)surface; TRACE("Created surface level %u @ %p.\n", i, surface); /* Calculate the next mipmap level. */ tmp_w = max(1, tmp_w >> 1); tmp_h = max(1, tmp_h >> 1); } texture->baseTexture.internal_preload = texture_internal_preload; return WINED3D_OK; }