static HRESULT volume_init(struct wined3d_volume *volume, struct wined3d_device *device, UINT width, UINT height, UINT depth, DWORD usage, enum wined3d_format_id format_id, enum wined3d_pool pool, void *parent, const struct wined3d_parent_ops *parent_ops) { const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; const struct wined3d_format *format = wined3d_get_format(gl_info, format_id); HRESULT hr; if (!gl_info->supported[EXT_TEXTURE3D]) { WARN("Volume cannot be created - no volume texture support.\n"); return WINED3DERR_INVALIDCALL; } hr = resource_init(&volume->resource, device, WINED3D_RTYPE_VOLUME, format, WINED3D_MULTISAMPLE_NONE, 0, usage, pool, width, height, depth, width * height * depth * format->byte_count, parent, parent_ops, &volume_resource_ops); if (FAILED(hr)) { WARN("Failed to initialize resource, returning %#x.\n", hr); return hr; } volume->lockable = TRUE; volume->locked = FALSE; memset(&volume->lockedBox, 0, sizeof(volume->lockedBox)); volume->dirty = TRUE; volume_add_dirty_box(volume, NULL); return WINED3D_OK; }
HRESULT wined3d_volume_init(struct wined3d_volume *volume, struct wined3d_texture *container, const struct wined3d_resource_desc *desc, UINT level) { struct wined3d_device *device = container->resource.device; const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; const struct wined3d_format *format = wined3d_get_format(gl_info, desc->format); HRESULT hr; UINT size; size = wined3d_format_calculate_size(format, device->surface_alignment, desc->width, desc->height, desc->depth); if (FAILED(hr = resource_init(&volume->resource, device, WINED3D_RTYPE_VOLUME, format, WINED3D_MULTISAMPLE_NONE, 0, desc->usage, desc->pool, desc->width, desc->height, desc->depth, size, NULL, &wined3d_null_parent_ops, &volume_resource_ops))) { WARN("Failed to initialize resource, returning %#x.\n", hr); return hr; } if (container->resource.map_binding == WINED3D_LOCATION_BUFFER) wined3d_resource_free_sysmem(&volume->resource); volume->texture_level = level; container->sub_resources[level].locations = WINED3D_LOCATION_DISCARDED; volume->container = container; return WINED3D_OK; }
static HRESULT wined3d_rendertarget_view_init(struct wined3d_rendertarget_view *view, const struct wined3d_rendertarget_view_desc *desc, struct wined3d_resource *resource, void *parent, const struct wined3d_parent_ops *parent_ops) { const struct wined3d_gl_info *gl_info = &resource->device->adapter->gl_info; view->refcount = 1; view->parent = parent; view->parent_ops = parent_ops; view->format = wined3d_get_format(gl_info, desc->format_id); view->format_flags = view->format->flags[resource->gl_type]; if (wined3d_format_is_typeless(view->format)) { WARN("Trying to create view for typeless format %s.\n", debug_d3dformat(view->format->id)); return E_INVALIDARG; } if (resource->type == WINED3D_RTYPE_BUFFER) { view->sub_resource_idx = 0; view->buffer_offset = desc->u.buffer.start_idx; view->width = desc->u.buffer.count; view->height = 1; view->depth = 1; } else { struct wined3d_texture *texture = texture_from_resource(resource); unsigned int depth_or_layer_count; if (resource->type == WINED3D_RTYPE_TEXTURE_3D) depth_or_layer_count = wined3d_texture_get_level_depth(texture, desc->u.texture.level_idx); else depth_or_layer_count = texture->layer_count; if (desc->u.texture.level_idx >= texture->level_count || desc->u.texture.layer_idx >= depth_or_layer_count || !desc->u.texture.layer_count || desc->u.texture.layer_count > depth_or_layer_count - desc->u.texture.layer_idx) return E_INVALIDARG; view->sub_resource_idx = desc->u.texture.level_idx; if (resource->type != WINED3D_RTYPE_TEXTURE_3D) view->sub_resource_idx += desc->u.texture.layer_idx * texture->level_count; view->buffer_offset = 0; view->width = wined3d_texture_get_level_width(texture, desc->u.texture.level_idx); view->height = wined3d_texture_get_level_height(texture, desc->u.texture.level_idx); view->depth = desc->u.texture.layer_count; } wined3d_resource_incref(view->resource = resource); return WINED3D_OK; }
static HRESULT volume_init(struct wined3d_volume *volume, struct wined3d_device *device, UINT width, UINT height, UINT depth, UINT level, DWORD usage, enum wined3d_format_id format_id, enum wined3d_pool pool, void *parent, const struct wined3d_parent_ops *parent_ops) { const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; const struct wined3d_format *format = wined3d_get_format(gl_info, format_id); HRESULT hr; UINT size; if (!gl_info->supported[EXT_TEXTURE3D]) { WARN("Volume cannot be created - no volume texture support.\n"); return WINED3DERR_INVALIDCALL; } /* TODO: Write tests for other resources and move this check * to resource_init, if applicable. */ if (usage & WINED3DUSAGE_DYNAMIC && (pool == WINED3D_POOL_MANAGED || pool == WINED3D_POOL_SCRATCH)) { WARN("Attempted to create a DYNAMIC texture in pool %u.\n", pool); return WINED3DERR_INVALIDCALL; } size = wined3d_format_calculate_size(format, device->surface_alignment, width, height, depth); hr = resource_init(&volume->resource, device, WINED3D_RTYPE_VOLUME, format, WINED3D_MULTISAMPLE_NONE, 0, usage, pool, width, height, depth, size, parent, parent_ops, &volume_resource_ops); if (FAILED(hr)) { WARN("Failed to initialize resource, returning %#x.\n", hr); return hr; } volume->texture_level = level; volume->locations = WINED3D_LOCATION_DISCARDED; if (pool == WINED3D_POOL_DEFAULT && usage & WINED3DUSAGE_DYNAMIC && gl_info->supported[ARB_PIXEL_BUFFER_OBJECT]) { wined3d_resource_free_sysmem(volume->resource.heap_memory); volume->resource.heap_memory = NULL; volume->resource.allocatedMemory = NULL; volume->flags |= WINED3D_VFLAG_PBO; } return WINED3D_OK; }
static HRESULT volume_init(struct wined3d_volume *volume, struct wined3d_texture *container, const struct wined3d_resource_desc *desc, UINT level) { struct wined3d_device *device = container->resource.device; const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; const struct wined3d_format *format = wined3d_get_format(gl_info, desc->format); HRESULT hr; UINT size; if (!gl_info->supported[EXT_TEXTURE3D]) { WARN("Volume cannot be created - no volume texture support.\n"); return WINED3DERR_INVALIDCALL; } /* TODO: Write tests for other resources and move this check * to resource_init, if applicable. */ if (desc->usage & WINED3DUSAGE_DYNAMIC && (desc->pool == WINED3D_POOL_MANAGED || desc->pool == WINED3D_POOL_SCRATCH)) { WARN("Attempted to create a DYNAMIC texture in pool %s.\n", debug_d3dpool(desc->pool)); return WINED3DERR_INVALIDCALL; } size = wined3d_format_calculate_size(format, device->surface_alignment, desc->width, desc->height, desc->depth); if (FAILED(hr = resource_init(&volume->resource, device, WINED3D_RTYPE_VOLUME, format, WINED3D_MULTISAMPLE_NONE, 0, desc->usage, desc->pool, desc->width, desc->height, desc->depth, size, NULL, &wined3d_null_parent_ops, &volume_resource_ops))) { WARN("Failed to initialize resource, returning %#x.\n", hr); return hr; } volume->texture_level = level; volume->locations = WINED3D_LOCATION_DISCARDED; if (desc->pool == WINED3D_POOL_DEFAULT && desc->usage & WINED3DUSAGE_DYNAMIC && gl_info->supported[ARB_PIXEL_BUFFER_OBJECT] && !format->convert) { wined3d_resource_free_sysmem(&volume->resource); volume->flags |= WINED3D_VFLAG_PBO; } volume->container = container; return WINED3D_OK; }
static HRESULT wined3d_rendertarget_view_init(struct wined3d_rendertarget_view *view, const struct wined3d_rendertarget_view_desc *desc, struct wined3d_resource *resource, void *parent, const struct wined3d_parent_ops *parent_ops) { const struct wined3d_gl_info *gl_info = &resource->device->adapter->gl_info; view->refcount = 1; view->parent = parent; view->parent_ops = parent_ops; view->format = wined3d_get_format(gl_info, desc->format_id); view->format_flags = view->format->flags[resource->gl_type]; if (resource->type == WINED3D_RTYPE_BUFFER) { view->sub_resource_idx = 0; view->buffer_offset = desc->u.buffer.start_idx; view->width = desc->u.buffer.count; view->height = 1; view->depth = 1; } else { struct wined3d_texture *texture = texture_from_resource(resource); if (desc->u.texture.level_idx >= texture->level_count || desc->u.texture.layer_idx >= texture->layer_count || desc->u.texture.layer_count > texture->layer_count - desc->u.texture.layer_idx) return WINED3DERR_INVALIDCALL; view->sub_resource_idx = desc->u.texture.layer_idx * texture->level_count + desc->u.texture.level_idx; view->buffer_offset = 0; view->width = wined3d_texture_get_level_width(texture, desc->u.texture.level_idx); view->height = wined3d_texture_get_level_height(texture, desc->u.texture.level_idx); view->depth = desc->u.texture.layer_count; } wined3d_resource_incref(view->resource = resource); return WINED3D_OK; }
static HRESULT wined3d_unordered_access_view_init(struct wined3d_unordered_access_view *view, const struct wined3d_unordered_access_view_desc *desc, struct wined3d_resource *resource, void *parent, const struct wined3d_parent_ops *parent_ops) { const struct wined3d_gl_info *gl_info = &resource->device->adapter->gl_info; view->refcount = 1; view->parent = parent; view->parent_ops = parent_ops; view->format = wined3d_get_format(gl_info, desc->format_id); if (wined3d_format_is_typeless(view->format)) { WARN("Trying to create view for typeless format %s.\n", debug_d3dformat(view->format->id)); return E_INVALIDARG; } if (resource->type != WINED3D_RTYPE_BUFFER) { struct wined3d_texture *texture = texture_from_resource(resource); unsigned int depth_or_layer_count; if (resource->type == WINED3D_RTYPE_TEXTURE_3D) depth_or_layer_count = wined3d_texture_get_level_depth(texture, desc->u.texture.level_idx); else depth_or_layer_count = texture->layer_count; if (desc->u.texture.level_idx >= texture->level_count || desc->u.texture.layer_idx >= depth_or_layer_count || !desc->u.texture.layer_count || desc->u.texture.layer_count > depth_or_layer_count - desc->u.texture.layer_idx) return E_INVALIDARG; } wined3d_resource_incref(view->resource = resource); return WINED3D_OK; }
HRESULT volume_init(IWineD3DVolumeImpl *volume, IWineD3DDeviceImpl *device, UINT width, UINT height, UINT depth, DWORD usage, enum wined3d_format_id format_id, WINED3DPOOL pool, void *parent, const struct wined3d_parent_ops *parent_ops) { const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; const struct wined3d_format *format = wined3d_get_format(gl_info, format_id); HRESULT hr; if (!gl_info->supported[EXT_TEXTURE3D]) { WARN("Volume cannot be created - no volume texture support.\n"); return WINED3DERR_INVALIDCALL; } volume->lpVtbl = &IWineD3DVolume_Vtbl; hr = resource_init((IWineD3DResource *)volume, WINED3DRTYPE_VOLUME, device, width * height * depth * format->byte_count, usage, format, pool, parent, parent_ops); if (FAILED(hr)) { WARN("Failed to initialize resource, returning %#x.\n", hr); return hr; } volume->currentDesc.Width = width; volume->currentDesc.Height = height; volume->currentDesc.Depth = depth; volume->lockable = TRUE; volume->locked = FALSE; memset(&volume->lockedBox, 0, sizeof(volume->lockedBox)); volume->dirty = TRUE; volume_add_dirty_box((IWineD3DVolume *)volume, NULL); return WINED3D_OK; }
static void wined3d_rendertarget_view_init(struct wined3d_rendertarget_view *view, const struct wined3d_rendertarget_view_desc *desc, struct wined3d_resource *resource, void *parent, const struct wined3d_parent_ops *parent_ops) { const struct wined3d_gl_info *gl_info = &resource->device->adapter->gl_info; view->refcount = 1; view->resource = resource; wined3d_resource_incref(resource); view->parent = parent; view->parent_ops = parent_ops; view->format = wined3d_get_format(gl_info, desc->format_id); view->format_flags = view->format->flags[resource->gl_type]; if (resource->type == WINED3D_RTYPE_BUFFER) { view->sub_resource_idx = 0; view->buffer_offset = desc->u.buffer.start_idx; view->width = desc->u.buffer.count; view->height = 1; view->depth = 1; } else { struct wined3d_texture *texture = wined3d_texture_from_resource(resource); struct wined3d_resource *sub_resource; view->sub_resource_idx = desc->u.texture.layer_idx * texture->level_count + desc->u.texture.level_idx; sub_resource = wined3d_texture_get_sub_resource(texture, view->sub_resource_idx); view->buffer_offset = 0; view->width = sub_resource->width; view->height = sub_resource->height; view->depth = desc->u.texture.layer_count; } }
HRESULT texture_init(IWineD3DBaseTextureImpl *texture, UINT width, UINT height, UINT levels, IWineD3DDeviceImpl *device, DWORD usage, enum wined3d_format_id format_id, WINED3DPOOL pool, void *parent, const struct wined3d_parent_ops *parent_ops) { const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; const struct wined3d_format *format = wined3d_get_format(gl_info, format_id); 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_id) { 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, &texture_ops, 1, levels, WINED3DRTYPE_TEXTURE, device, usage, format, pool, parent, parent_ops, &texture_resource_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->baseTexture.target = GL_TEXTURE_2D; texture->baseTexture.cond_np2 = TRUE; texture->baseTexture.minMipLookup = minMipLookup_noFilter; } else if (gl_info->supported[ARB_TEXTURE_RECTANGLE] && (width != pow2_width || height != pow2_height) && !(format->id == 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->baseTexture.target = GL_TEXTURE_RECTANGLE_ARB; texture->baseTexture.cond_np2 = TRUE; if (texture->resource.format->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->baseTexture.target = GL_TEXTURE_2D; texture->baseTexture.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->id, usage, pool, i, 0, &surface); if (FAILED(hr)) { FIXME("Failed to create surface %p, hr %#x\n", texture, hr); texture_cleanup(texture); return hr; } surface_set_container((IWineD3DSurfaceImpl *)surface, WINED3D_CONTAINER_TEXTURE, (IWineD3DBase *)texture); surface_set_texture_target((IWineD3DSurfaceImpl *)surface, texture->baseTexture.target); texture->baseTexture.sub_resources[i] = &((IWineD3DSurfaceImpl *)surface)->resource; 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); } return WINED3D_OK; }
HRESULT volumetexture_init(IWineD3DBaseTextureImpl *texture, UINT width, UINT height, UINT depth, UINT levels, IWineD3DDeviceImpl *device, DWORD usage, enum wined3d_format_id format_id, WINED3DPOOL pool, void *parent, const struct wined3d_parent_ops *parent_ops) { const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; const struct wined3d_format *format = wined3d_get_format(gl_info, format_id); UINT tmp_w, tmp_h, tmp_d; 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_id) { WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN.\n", texture); return WINED3DERR_INVALIDCALL; } if (!gl_info->supported[EXT_TEXTURE3D]) { WARN("(%p) : Texture cannot be created - no volume texture support.\n", texture); return WINED3DERR_INVALIDCALL; } /* Calculate levels for mip mapping. */ if (usage & WINED3DUSAGE_AUTOGENMIPMAP) { if (!gl_info->supported[SGIS_GENERATE_MIPMAP]) { WARN("No mipmap generation support, returning D3DERR_INVALIDCALL.\n"); return WINED3DERR_INVALIDCALL; } if (levels > 1) { WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL.\n"); return WINED3DERR_INVALIDCALL; } levels = 1; } else if (!levels) { levels = wined3d_log2i(max(max(width, height), depth)) + 1; TRACE("Calculated levels = %u.\n", levels); } texture->lpVtbl = &IWineD3DVolumeTexture_Vtbl; hr = basetexture_init((IWineD3DBaseTextureImpl *)texture, &volumetexture_ops, 1, levels, WINED3DRTYPE_VOLUMETEXTURE, device, usage, format, pool, parent, parent_ops, &volumetexture_resource_ops); if (FAILED(hr)) { WARN("Failed to initialize basetexture, returning %#x.\n", hr); return hr; } /* Is NP2 support for volumes needed? */ 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->baseTexture.target = GL_TEXTURE_3D; /* Generate all the surfaces. */ tmp_w = width; tmp_h = height; tmp_d = depth; for (i = 0; i < texture->baseTexture.level_count; ++i) { IWineD3DVolume *volume; /* Create the volume. */ hr = IWineD3DDeviceParent_CreateVolume(device->device_parent, parent, tmp_w, tmp_h, tmp_d, format_id, pool, usage, &volume); if (FAILED(hr)) { ERR("Creating a volume for the volume texture failed, hr %#x.\n", hr); volumetexture_cleanup(texture); return hr; } /* Set its container to this texture. */ volume_set_container((IWineD3DVolumeImpl *)volume, texture); texture->baseTexture.sub_resources[i] = &((IWineD3DVolumeImpl *)volume)->resource; /* Calculate the next mipmap level. */ tmp_w = max(1, tmp_w >> 1); tmp_h = max(1, tmp_h >> 1); tmp_d = max(1, tmp_d >> 1); } return WINED3D_OK; }
static const struct wined3d_format *validate_resource_view(const struct wined3d_view_desc *desc, struct wined3d_resource *resource, BOOL mip_slice, BOOL allow_srgb_toggle) { const struct wined3d_gl_info *gl_info = &resource->device->adapter->gl_info; const struct wined3d_format *format; format = wined3d_get_format(gl_info, desc->format_id, resource->usage); if (resource->type == WINED3D_RTYPE_BUFFER && (desc->flags & WINED3D_VIEW_BUFFER_RAW)) { if (format->id != WINED3DFMT_R32_TYPELESS) { WARN("Invalid format %s for raw buffer view.\n", debug_d3dformat(format->id)); return NULL; } format = wined3d_get_format(gl_info, WINED3DFMT_R32_UINT, resource->usage); } if (wined3d_format_is_typeless(format)) { WARN("Trying to create view for typeless format %s.\n", debug_d3dformat(format->id)); return NULL; } if (resource->type == WINED3D_RTYPE_BUFFER) { struct wined3d_buffer *buffer = buffer_from_resource(resource); unsigned int buffer_size, element_size; if (buffer->desc.structure_byte_stride) { if (desc->format_id != WINED3DFMT_UNKNOWN) { WARN("Invalid format %s for structured buffer view.\n", debug_d3dformat(desc->format_id)); return NULL; } format = wined3d_get_format(gl_info, WINED3DFMT_R32_UINT, resource->usage); element_size = buffer->desc.structure_byte_stride; } else { element_size = format->byte_count; } if (!element_size) return NULL; buffer_size = buffer->resource.size / element_size; if (desc->u.buffer.start_idx >= buffer_size || desc->u.buffer.count > buffer_size - desc->u.buffer.start_idx) return NULL; } else { struct wined3d_texture *texture = texture_from_resource(resource); unsigned int depth_or_layer_count; if (resource->format->id != format->id && !wined3d_format_is_typeless(resource->format) && (!allow_srgb_toggle || !wined3d_formats_are_srgb_variants(resource->format->id, format->id))) { WARN("Trying to create incompatible view for non typeless format %s.\n", debug_d3dformat(format->id)); return NULL; } if (mip_slice && resource->type == WINED3D_RTYPE_TEXTURE_3D) depth_or_layer_count = wined3d_texture_get_level_depth(texture, desc->u.texture.level_idx); else depth_or_layer_count = texture->layer_count; if (!desc->u.texture.level_count || (mip_slice && desc->u.texture.level_count != 1) || desc->u.texture.level_idx >= texture->level_count || desc->u.texture.level_count > texture->level_count - desc->u.texture.level_idx || !desc->u.texture.layer_count || desc->u.texture.layer_idx >= depth_or_layer_count || desc->u.texture.layer_count > depth_or_layer_count - desc->u.texture.layer_idx) return NULL; } return format; }
static HRESULT swapchain_gl_present(struct wined3d_swapchain *swapchain, const RECT *src_rect_in, const RECT *dst_rect_in, const RGNDATA *dirty_region, DWORD flags) { struct wined3d_surface *back_buffer = swapchain->back_buffers[0]; const struct wined3d_fb_state *fb = &swapchain->device->fb; const struct wined3d_gl_info *gl_info; struct wined3d_context *context; RECT src_rect, dst_rect; BOOL render_to_fbo; context = context_acquire(swapchain->device, back_buffer); if (!context->valid) { context_release(context); WARN("Invalid context, skipping present.\n"); return WINED3D_OK; } gl_info = context->gl_info; /* Render the cursor onto the back buffer, using our nifty directdraw blitting code :-) */ if (swapchain->device->bCursorVisible && swapchain->device->cursorTexture && !swapchain->device->hardwareCursor) { struct wined3d_surface cursor; RECT destRect = { swapchain->device->xScreenSpace - swapchain->device->xHotSpot, swapchain->device->yScreenSpace - swapchain->device->yHotSpot, swapchain->device->xScreenSpace + swapchain->device->cursorWidth - swapchain->device->xHotSpot, swapchain->device->yScreenSpace + swapchain->device->cursorHeight - swapchain->device->yHotSpot, }; TRACE("Rendering the cursor. Creating fake surface at %p\n", &cursor); /* Build a fake surface to call the Blitting code. It is not possible to use the interface passed by * the application because we are only supposed to copy the information out. Using a fake surface * allows to use the Blitting engine and avoid copying the whole texture -> render target blitting code. */ memset(&cursor, 0, sizeof(cursor)); cursor.resource.ref = 1; cursor.resource.device = swapchain->device; cursor.resource.pool = WINED3D_POOL_SCRATCH; cursor.resource.format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM); cursor.resource.type = WINED3D_RTYPE_SURFACE; cursor.texture_name = swapchain->device->cursorTexture; cursor.texture_target = GL_TEXTURE_2D; cursor.texture_level = 0; cursor.resource.width = swapchain->device->cursorWidth; cursor.resource.height = swapchain->device->cursorHeight; /* The cursor must have pow2 sizes */ cursor.pow2Width = cursor.resource.width; cursor.pow2Height = cursor.resource.height; /* The surface is in the texture */ cursor.flags |= SFLAG_INTEXTURE; /* DDBLT_KEYSRC will cause BltOverride to enable the alpha test with GL_NOTEQUAL, 0.0, * which is exactly what we want :-) */ if (swapchain->desc.windowed) MapWindowPoints(NULL, swapchain->win_handle, (POINT *)&destRect, 2); wined3d_surface_blt(back_buffer, &destRect, &cursor, NULL, WINEDDBLT_KEYSRC, NULL, WINED3D_TEXF_POINT); } if (swapchain->device->logo_surface) { struct wined3d_surface *src_surface = swapchain->device->logo_surface; RECT rect = {0, 0, src_surface->resource.width, src_surface->resource.height}; /* Blit the logo into the upper left corner of the drawable. */ wined3d_surface_blt(back_buffer, &rect, src_surface, &rect, WINEDDBLT_KEYSRC, NULL, WINED3D_TEXF_POINT); } TRACE("Presenting HDC %p.\n", context->hdc); render_to_fbo = swapchain->render_to_fbo; if (src_rect_in) { src_rect = *src_rect_in; if (!render_to_fbo && (src_rect.left || src_rect.top || src_rect.right != swapchain->desc.backbuffer_width || src_rect.bottom != swapchain->desc.backbuffer_height)) { render_to_fbo = TRUE; } } else { src_rect.left = 0; src_rect.top = 0; src_rect.right = swapchain->desc.backbuffer_width; src_rect.bottom = swapchain->desc.backbuffer_height; } if (dst_rect_in) dst_rect = *dst_rect_in; else GetClientRect(swapchain->win_handle, &dst_rect); if (!render_to_fbo && (dst_rect.left || dst_rect.top || dst_rect.right != swapchain->desc.backbuffer_width || dst_rect.bottom != swapchain->desc.backbuffer_height)) render_to_fbo = TRUE; /* Rendering to a window of different size, presenting partial rectangles, * or rendering to a different window needs help from FBO_blit or a textured * draw. Render the swapchain to a FBO in the future. * * Note that FBO_blit from the backbuffer to the frontbuffer cannot solve * all these issues - this fails if the window is smaller than the backbuffer. */ if (!swapchain->render_to_fbo && render_to_fbo && wined3d_settings.offscreen_rendering_mode == ORM_FBO) { surface_load_location(back_buffer, SFLAG_INTEXTURE, NULL); surface_modify_location(back_buffer, SFLAG_INDRAWABLE, FALSE); swapchain->render_to_fbo = TRUE; swapchain_update_draw_bindings(swapchain); } else { surface_load_location(back_buffer, back_buffer->draw_binding, NULL); } if (swapchain->render_to_fbo) { /* This codepath should only be hit with the COPY swapeffect. Otherwise a backbuffer- * window size mismatch is impossible(fullscreen) and src and dst rectangles are * not allowed(they need the COPY swapeffect) * * The DISCARD swap effect is ok as well since any backbuffer content is allowed after * the swap. */ if (swapchain->desc.swap_effect == WINED3D_SWAP_EFFECT_FLIP) FIXME("Render-to-fbo with WINED3D_SWAP_EFFECT_FLIP\n"); swapchain_blit(swapchain, context, &src_rect, &dst_rect); } if (swapchain->num_contexts > 1) wglFinish(); SwapBuffers(context->hdc); /* TODO: cycle through the swapchain buffers */ TRACE("SwapBuffers called, Starting new frame\n"); /* FPS support */ if (TRACE_ON(fps)) { DWORD time = GetTickCount(); ++swapchain->frames; /* every 1.5 seconds */ if (time - swapchain->prev_time > 1500) { TRACE_(fps)("%p @ approx %.2ffps\n", swapchain, 1000.0 * swapchain->frames / (time - swapchain->prev_time)); swapchain->prev_time = time; swapchain->frames = 0; } } /* This is disabled, but the code left in for debug purposes. * * Since we're allowed to modify the new back buffer on a D3DSWAPEFFECT_DISCARD flip, * we can clear it with some ugly color to make bad drawing visible and ease debugging. * The Debug runtime does the same on Windows. However, a few games do not redraw the * screen properly, like Max Payne 2, which leaves a few pixels undefined. * * Tests show that the content of the back buffer after a discard flip is indeed not * reliable, so no game can depend on the exact content. However, it resembles the * old contents in some way, for example by showing fragments at other locations. In * general, the color theme is still intact. So Max payne, which draws rather dark scenes * gets a dark background image. If we clear it with a bright ugly color, the game's * bug shows up much more than it does on Windows, and the players see single pixels * with wrong colors. * (The Max Payne bug has been confirmed on Windows with the debug runtime) */ if (FALSE && swapchain->desc.swap_effect == WINED3D_SWAP_EFFECT_DISCARD) { static const struct wined3d_color cyan = {0.0f, 1.0f, 1.0f, 1.0f}; TRACE("Clearing the color buffer with cyan color\n"); wined3d_device_clear(swapchain->device, 0, NULL, WINED3DCLEAR_TARGET, &cyan, 1.0f, 0); } if (!swapchain->render_to_fbo && ((swapchain->front_buffer->flags & SFLAG_INSYSMEM) || (back_buffer->flags & SFLAG_INSYSMEM))) { /* Both memory copies of the surfaces are ok, flip them around too instead of dirtifying * Doesn't work with render_to_fbo because we're not flipping */ struct wined3d_surface *front = swapchain->front_buffer; if (front->resource.size == back_buffer->resource.size) { DWORD fbflags; flip_surface(front, back_buffer); /* Tell the front buffer surface that is has been modified. However, * the other locations were preserved during that, so keep the flags. * This serves to update the emulated overlay, if any. */ fbflags = front->flags; surface_modify_location(front, SFLAG_INDRAWABLE, TRUE); front->flags = fbflags; } else { surface_modify_location(front, SFLAG_INDRAWABLE, TRUE); surface_modify_location(back_buffer, SFLAG_INDRAWABLE, TRUE); } } else { surface_modify_location(swapchain->front_buffer, SFLAG_INDRAWABLE, TRUE); /* If the swapeffect is DISCARD, the back buffer is undefined. That means the SYSMEM * and INTEXTURE copies can keep their old content if they have any defined content. * If the swapeffect is COPY, the content remains the same. If it is FLIP however, * the texture / sysmem copy needs to be reloaded from the drawable */ if (swapchain->desc.swap_effect == WINED3D_SWAP_EFFECT_FLIP) surface_modify_location(back_buffer, back_buffer->draw_binding, TRUE); } if (fb->depth_stencil) { if (swapchain->desc.flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL || fb->depth_stencil->flags & SFLAG_DISCARD) { surface_modify_ds_location(fb->depth_stencil, SFLAG_DISCARDED, fb->depth_stencil->resource.width, fb->depth_stencil->resource.height); if (fb->depth_stencil == swapchain->device->onscreen_depth_stencil) { wined3d_surface_decref(swapchain->device->onscreen_depth_stencil); swapchain->device->onscreen_depth_stencil = NULL; } } } context_release(context); TRACE("returning\n"); return WINED3D_OK; }
HRESULT vertexdeclaration_init(IWineD3DVertexDeclarationImpl *declaration, IWineD3DDeviceImpl *device, const WINED3DVERTEXELEMENT *elements, UINT element_count, void *parent, const struct wined3d_parent_ops *parent_ops) { const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; WORD preloaded = 0; /* MAX_STREAMS, 16 */ unsigned int i; if (TRACE_ON(d3d_decl)) { for (i = 0; i < element_count; ++i) { dump_wined3dvertexelement(elements + i); } } declaration->lpVtbl = &IWineD3DVertexDeclaration_Vtbl; declaration->ref = 1; declaration->parent = parent; declaration->parent_ops = parent_ops; declaration->device = device; declaration->elements = HeapAlloc(GetProcessHeap(), 0, sizeof(*declaration->elements) * element_count); if (!declaration->elements) { ERR("Failed to allocate elements memory.\n"); return E_OUTOFMEMORY; } declaration->element_count = element_count; /* Do some static analysis on the elements to make reading the * declaration more comfortable for the drawing code. */ for (i = 0; i < element_count; ++i) { struct wined3d_vertex_declaration_element *e = &declaration->elements[i]; e->format = wined3d_get_format(gl_info, elements[i].format); e->ffp_valid = declaration_element_valid_ffp(&elements[i]); e->input_slot = elements[i].input_slot; e->offset = elements[i].offset; e->output_slot = elements[i].output_slot; e->method = elements[i].method; e->usage = elements[i].usage; e->usage_idx = elements[i].usage_idx; if (e->usage == WINED3DDECLUSAGE_POSITIONT) declaration->position_transformed = TRUE; /* Find the streams used in the declaration. The vertex buffers have * to be loaded when drawing, but filter tesselation pseudo streams. */ if (e->input_slot >= MAX_STREAMS) continue; if (!e->format->gl_vtx_format) { FIXME("The application tries to use an unsupported format (%s), returning E_FAIL.\n", debug_d3dformat(elements[i].format)); HeapFree(GetProcessHeap(), 0, declaration->elements); return E_FAIL; } if (e->offset & 0x3) { WARN("Declaration element %u is not 4 byte aligned(%u), returning E_FAIL.\n", i, e->offset); HeapFree(GetProcessHeap(), 0, declaration->elements); return E_FAIL; } if (!(preloaded & (1 << e->input_slot))) { declaration->streams[declaration->num_streams] = e->input_slot; ++declaration->num_streams; preloaded |= 1 << e->input_slot; } if (elements[i].format == WINED3DFMT_R16G16_FLOAT || elements[i].format == WINED3DFMT_R16G16B16A16_FLOAT) { if (!gl_info->supported[ARB_HALF_FLOAT_VERTEX]) declaration->half_float_conv_needed = TRUE; } } return WINED3D_OK; }
static HRESULT wined3d_shader_resource_view_init(struct wined3d_shader_resource_view *view, const struct wined3d_shader_resource_view_desc *desc, struct wined3d_resource *resource, void *parent, const struct wined3d_parent_ops *parent_ops) { static const struct { GLenum texture_target; unsigned int view_flags; GLenum view_target; } view_types[] = { {GL_TEXTURE_1D, 0, GL_TEXTURE_1D}, {GL_TEXTURE_1D, WINED3D_VIEW_TEXTURE_ARRAY, GL_TEXTURE_1D_ARRAY}, {GL_TEXTURE_1D_ARRAY, 0, GL_TEXTURE_1D}, {GL_TEXTURE_1D_ARRAY, WINED3D_VIEW_TEXTURE_ARRAY, GL_TEXTURE_1D_ARRAY}, {GL_TEXTURE_2D, 0, GL_TEXTURE_2D}, {GL_TEXTURE_2D, WINED3D_VIEW_TEXTURE_ARRAY, GL_TEXTURE_2D_ARRAY}, {GL_TEXTURE_2D_ARRAY, 0, GL_TEXTURE_2D}, {GL_TEXTURE_2D_ARRAY, WINED3D_VIEW_TEXTURE_ARRAY, GL_TEXTURE_2D_ARRAY}, {GL_TEXTURE_2D_ARRAY, WINED3D_VIEW_TEXTURE_CUBE, GL_TEXTURE_CUBE_MAP}, {GL_TEXTURE_3D, 0, GL_TEXTURE_3D}, }; const struct wined3d_gl_info *gl_info = &resource->device->adapter->gl_info; const struct wined3d_format *view_format; view_format = wined3d_get_format(gl_info, desc->format_id); if (wined3d_format_is_typeless(view_format)) { WARN("Trying to create view for typeless format %s.\n", debug_d3dformat(view_format->id)); return E_INVALIDARG; } view->refcount = 1; view->parent = parent; view->parent_ops = parent_ops; view->target = GL_NONE; view->object = 0; if (resource->type == WINED3D_RTYPE_BUFFER) { FIXME("Buffer shader resource views not supported.\n"); } else { struct wined3d_texture *texture = texture_from_resource(resource); unsigned int i; if (!desc->u.texture.level_count || desc->u.texture.level_idx >= texture->level_count || desc->u.texture.level_count > texture->level_count - desc->u.texture.level_idx || !desc->u.texture.layer_count || desc->u.texture.layer_idx >= texture->layer_count || desc->u.texture.layer_count > texture->layer_count - desc->u.texture.layer_idx) return E_INVALIDARG; view->target = texture->target; for (i = 0; i < ARRAY_SIZE(view_types); ++i) { if (view_types[i].texture_target == texture->target && view_types[i].view_flags == desc->flags) { view->target = view_types[i].view_target; break; } } if (i == ARRAY_SIZE(view_types)) FIXME("Unhandled view flags %#x for texture target %#x.\n", desc->flags, texture->target); if (resource->format->id == view_format->id && texture->target == view->target && !desc->u.texture.level_idx && desc->u.texture.level_count == texture->level_count && !desc->u.texture.layer_idx && desc->u.texture.layer_count == texture->layer_count) { TRACE("Creating identity shader resource view.\n"); } else if (texture->swapchain && texture->swapchain->desc.backbuffer_count > 1) { FIXME("Swapchain shader resource views not supported.\n"); } else if (resource->format->typeless_id == view_format->typeless_id && resource->format->gl_view_class == view_format->gl_view_class) { wined3d_shader_resource_view_create_texture_view(view, desc, texture, view_format); } else { FIXME("Shader resource view not supported, resource format %s, view format %s.\n", debug_d3dformat(resource->format->id), debug_d3dformat(view_format->id)); } } wined3d_resource_incref(view->resource = resource); return WINED3D_OK; }
static HRESULT swapchain_init(struct wined3d_swapchain *swapchain, struct wined3d_device *device, struct wined3d_swapchain_desc *desc, void *parent, const struct wined3d_parent_ops *parent_ops) { const struct wined3d_adapter *adapter = device->adapter; const struct wined3d_gl_info *gl_info = &adapter->gl_info; struct wined3d_resource_desc surface_desc; BOOL displaymode_set = FALSE; RECT client_rect; HWND window; HRESULT hr; UINT i; if (desc->backbuffer_count > WINED3DPRESENT_BACK_BUFFER_MAX) { FIXME("The application requested %u back buffers, this is not supported.\n", desc->backbuffer_count); return WINED3DERR_INVALIDCALL; } if (desc->backbuffer_count > 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"); } if (device->wined3d->flags & WINED3D_NO3D) swapchain->swapchain_ops = &swapchain_gdi_ops; else swapchain->swapchain_ops = &swapchain_gl_ops; window = desc->device_window ? desc->device_window : device->create_parms.focus_window; swapchain->device = device; swapchain->parent = parent; swapchain->parent_ops = parent_ops; swapchain->ref = 1; swapchain->win_handle = window; swapchain->device_window = window; if (FAILED(hr = wined3d_get_adapter_display_mode(device->wined3d, adapter->ordinal, &swapchain->original_mode, NULL))) { ERR("Failed to get current display mode, hr %#x.\n", hr); goto err; } GetClientRect(window, &client_rect); if (desc->windowed && (!desc->backbuffer_width || !desc->backbuffer_height || desc->backbuffer_format == WINED3DFMT_UNKNOWN)) { if (!desc->backbuffer_width) { desc->backbuffer_width = client_rect.right; TRACE("Updating width to %u.\n", desc->backbuffer_width); } if (!desc->backbuffer_height) { desc->backbuffer_height = client_rect.bottom; TRACE("Updating height to %u.\n", desc->backbuffer_height); } if (desc->backbuffer_format == WINED3DFMT_UNKNOWN) { desc->backbuffer_format = swapchain->original_mode.format_id; TRACE("Updating format to %s.\n", debug_d3dformat(swapchain->original_mode.format_id)); } } swapchain->desc = *desc; swapchain_update_render_to_fbo(swapchain); swapchain_update_surface(swapchain); TRACE("Creating front buffer.\n"); surface_desc.resource_type = WINED3D_RTYPE_SURFACE; surface_desc.format = swapchain->desc.backbuffer_format; surface_desc.multisample_type = swapchain->desc.multisample_type; surface_desc.multisample_quality = swapchain->desc.multisample_quality; surface_desc.usage = 0; surface_desc.pool = WINED3D_POOL_DEFAULT; surface_desc.width = swapchain->desc.backbuffer_width; surface_desc.height = swapchain->desc.backbuffer_height; surface_desc.depth = 1; surface_desc.size = 0; if (FAILED(hr = device->device_parent->ops->create_swapchain_surface(device->device_parent, parent, &surface_desc, &swapchain->front_buffer))) { WARN("Failed to create front buffer, hr %#x.\n", hr); goto err; } surface_set_swapchain(swapchain->front_buffer, swapchain); if (!(device->wined3d->flags & WINED3D_NO3D)) { surface_validate_location(swapchain->front_buffer, WINED3D_LOCATION_DRAWABLE); surface_invalidate_location(swapchain->front_buffer, ~WINED3D_LOCATION_DRAWABLE); } /* 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 (!desc->windowed) { struct wined3d_display_mode mode; /* Change the display settings */ mode.width = desc->backbuffer_width; mode.height = desc->backbuffer_height; mode.format_id = desc->backbuffer_format; mode.refresh_rate = desc->refresh_rate; mode.scanline_ordering = WINED3D_SCANLINE_ORDERING_UNKNOWN; if (FAILED(hr = wined3d_set_adapter_display_mode(device->wined3d, adapter->ordinal, &mode))) { WARN("Failed to set display mode, hr %#x.\n", hr); goto err; } displaymode_set = TRUE; } if (!(device->wined3d->flags & WINED3D_NO3D)) { static const enum wined3d_format_id formats[] = { WINED3DFMT_D24_UNORM_S8_UINT, WINED3DFMT_D32_UNORM, WINED3DFMT_R24_UNORM_X8_TYPELESS, WINED3DFMT_D16_UNORM, WINED3DFMT_S1_UINT_D15_UNORM }; 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; /* 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. */ for (i = 0; i < (sizeof(formats) / sizeof(*formats)); i++) { swapchain->ds_format = wined3d_get_format(gl_info, formats[i]); swapchain->context[0] = context_create(swapchain, swapchain->front_buffer, swapchain->ds_format); if (swapchain->context[0]) break; TRACE("Depth stencil format %s is not supported, trying next format\n", debug_d3dformat(formats[i])); } if (!swapchain->context[0]) { WARN("Failed to create context.\n"); hr = WINED3DERR_NOTAVAILABLE; goto err; } if (wined3d_settings.offscreen_rendering_mode != ORM_FBO && (!desc->enable_auto_depth_stencil || swapchain->desc.auto_depth_stencil_format != swapchain->ds_format->id)) { FIXME("Add OpenGL context recreation support to context_validate_onscreen_formats\n"); } context_release(swapchain->context[0]); } if (swapchain->desc.backbuffer_count > 0) { swapchain->back_buffers = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->back_buffers) * swapchain->desc.backbuffer_count); if (!swapchain->back_buffers) { ERR("Failed to allocate backbuffer array memory.\n"); hr = E_OUTOFMEMORY; goto err; } surface_desc.usage |= WINED3DUSAGE_RENDERTARGET; for (i = 0; i < swapchain->desc.backbuffer_count; ++i) { TRACE("Creating back buffer %u.\n", i); if (FAILED(hr = device->device_parent->ops->create_swapchain_surface(device->device_parent, parent, &surface_desc, &swapchain->back_buffers[i]))) { WARN("Failed to create back buffer %u, hr %#x.\n", i, hr); swapchain->desc.backbuffer_count = i; goto err; } surface_set_swapchain(swapchain->back_buffers[i], swapchain); } } /* Swapchains share the depth/stencil buffer, so only create a single depthstencil surface. */ if (desc->enable_auto_depth_stencil && !(device->wined3d->flags & WINED3D_NO3D)) { TRACE("Creating depth/stencil buffer.\n"); if (!device->auto_depth_stencil) { surface_desc.format = swapchain->desc.auto_depth_stencil_format; surface_desc.usage = WINED3DUSAGE_DEPTHSTENCIL; if (FAILED(hr = device->device_parent->ops->create_swapchain_surface(device->device_parent, device->device_parent, &surface_desc, &device->auto_depth_stencil))) { WARN("Failed to create the auto depth stencil, hr %#x.\n", hr); goto err; } } } wined3d_swapchain_get_gamma_ramp(swapchain, &swapchain->orig_gamma); return WINED3D_OK; err: if (displaymode_set) { if (FAILED(wined3d_set_adapter_display_mode(device->wined3d, adapter->ordinal, &swapchain->original_mode))) ERR("Failed to restore display mode.\n"); ClipCursor(NULL); } if (swapchain->back_buffers) { for (i = 0; i < swapchain->desc.backbuffer_count; ++i) { if (swapchain->back_buffers[i]) { surface_set_swapchain(swapchain->back_buffers[i], NULL); wined3d_surface_decref(swapchain->back_buffers[i]); } } HeapFree(GetProcessHeap(), 0, swapchain->back_buffers); } 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); } if (swapchain->front_buffer) { surface_set_swapchain(swapchain->front_buffer, NULL); wined3d_surface_decref(swapchain->front_buffer); } if (swapchain->surface && !GL_EXTCALL(wglDestroySurfaceWINE(swapchain->surface))) ERR("wglDestroySurfaceWINE failed to destroy surface %p\n", swapchain->surface); return hr; }
static HRESULT cubetexture_init(struct wined3d_texture *texture, UINT edge_length, UINT levels, struct wined3d_device *device, DWORD usage, enum wined3d_format_id format_id, enum wined3d_pool pool, void *parent, const struct wined3d_parent_ops *parent_ops) { const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; const struct wined3d_format *format = wined3d_get_format(gl_info, format_id); UINT pow2_edge_length; unsigned int i, j; UINT tmp_w; HRESULT hr; /* TODO: It should only be possible to create textures for formats * that are reported as supported. */ if (WINED3DFMT_UNKNOWN >= format_id) { WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN.\n", texture); return WINED3DERR_INVALIDCALL; } if (!gl_info->supported[ARB_TEXTURE_CUBE_MAP] && pool != WINED3D_POOL_SCRATCH) { WARN("(%p) : Tried to create not supported cube texture.\n", texture); return WINED3DERR_INVALIDCALL; } /* Calculate levels for mip mapping */ if (usage & WINED3DUSAGE_AUTOGENMIPMAP) { if (!gl_info->supported[SGIS_GENERATE_MIPMAP]) { WARN("No mipmap generation support, returning D3DERR_INVALIDCALL.\n"); return WINED3DERR_INVALIDCALL; } if (levels > 1) { WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL.\n"); return WINED3DERR_INVALIDCALL; } levels = 1; } else if (!levels) { levels = wined3d_log2i(edge_length) + 1; TRACE("Calculated levels = %u.\n", levels); } hr = wined3d_texture_init(texture, &texture2d_ops, 6, levels, WINED3D_RTYPE_CUBE_TEXTURE, device, usage, format, pool, parent, parent_ops, &texture2d_resource_ops); if (FAILED(hr)) { WARN("Failed to initialize texture, returning %#x\n", hr); return hr; } /* Find the nearest pow2 match. */ pow2_edge_length = 1; while (pow2_edge_length < edge_length) pow2_edge_length <<= 1; if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || (edge_length == pow2_edge_length)) { /* Precalculated scaling for 'faked' non power of two texture coords. */ texture->pow2_matrix[0] = 1.0f; texture->pow2_matrix[5] = 1.0f; texture->pow2_matrix[10] = 1.0f; texture->pow2_matrix[15] = 1.0f; } else { /* Precalculated scaling for 'faked' non power of two texture coords. */ texture->pow2_matrix[0] = ((float)edge_length) / ((float)pow2_edge_length); texture->pow2_matrix[5] = ((float)edge_length) / ((float)pow2_edge_length); texture->pow2_matrix[10] = ((float)edge_length) / ((float)pow2_edge_length); texture->pow2_matrix[15] = 1.0f; texture->flags &= ~WINED3D_TEXTURE_POW2_MAT_IDENT; } texture->target = GL_TEXTURE_CUBE_MAP_ARB; /* Generate all the surfaces. */ tmp_w = edge_length; for (i = 0; i < texture->level_count; ++i) { /* Create the 6 faces. */ for (j = 0; j < 6; ++j) { static const GLenum cube_targets[6] = { GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB, GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB, GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB, }; UINT idx = j * texture->level_count + i; struct wined3d_surface *surface; if (FAILED(hr = device->device_parent->ops->create_texture_surface(device->device_parent, parent, tmp_w, tmp_w, format_id, usage, pool, idx, &surface))) { FIXME("(%p) Failed to create surface, hr %#x.\n", texture, hr); wined3d_texture_cleanup(texture); return hr; } surface_set_container(surface, WINED3D_CONTAINER_TEXTURE, texture); surface_set_texture_target(surface, cube_targets[j], i); texture->sub_resources[idx] = &surface->resource; TRACE("Created surface level %u @ %p.\n", i, surface); } tmp_w = max(1, tmp_w >> 1); } return WINED3D_OK; }
HRESULT swapchain_create_context_cs(struct wined3d_device *device, struct wined3d_swapchain *swapchain) { const struct wined3d_adapter *adapter = device->adapter; unsigned int i; static const enum wined3d_format_id formats[] = { WINED3DFMT_D24_UNORM_S8_UINT, WINED3DFMT_D32_UNORM, WINED3DFMT_R24_UNORM_X8_TYPELESS, WINED3DFMT_D16_UNORM, WINED3DFMT_S1_UINT_D15_UNORM }; const struct wined3d_gl_info *gl_info = &adapter->gl_info; swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context)); if (!swapchain->context) { ERR("Failed to create the context array.\n"); return E_OUTOFMEMORY; } swapchain->num_contexts = 1; /* 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. */ for (i = 0; i < (sizeof(formats) / sizeof(*formats)); i++) { swapchain->ds_format = wined3d_get_format(gl_info, formats[i]); swapchain->context[0] = context_create(swapchain, swapchain->front_buffer, swapchain->ds_format); if (swapchain->context[0]) break; TRACE("Depth stencil format %s is not supported, trying next format\n", debug_d3dformat(formats[i])); } if (!swapchain->context[0]) { WARN("Failed to create context.\n"); HeapFree(GetProcessHeap(), 0, swapchain->context); swapchain->context = NULL; return WINED3DERR_NOTAVAILABLE; } if (wined3d_settings.offscreen_rendering_mode != ORM_FBO && (!swapchain->desc.enable_auto_depth_stencil || swapchain->desc.auto_depth_stencil_format != swapchain->ds_format->id)) { FIXME("Add OpenGL context recreation support to context_validate_onscreen_formats\n"); } context_release(swapchain->context[0]); return WINED3D_OK; }
/* Do not call while under the GL lock. */ static HRESULT swapchain_init(struct wined3d_swapchain *swapchain, enum wined3d_surface_type surface_type, struct wined3d_device *device, struct wined3d_swapchain_desc *desc, void *parent, const struct wined3d_parent_ops *parent_ops) { const struct wined3d_adapter *adapter = device->adapter; const struct wined3d_format *format; struct wined3d_display_mode mode; BOOL displaymode_set = FALSE; RECT client_rect; HWND window; HRESULT hr; UINT i; if (desc->backbuffer_count > WINED3DPRESENT_BACK_BUFFER_MAX) { FIXME("The application requested %u back buffers, this is not supported.\n", desc->backbuffer_count); return WINED3DERR_INVALIDCALL; } if (desc->backbuffer_count > 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 WINED3D_SURFACE_TYPE_GDI: swapchain->swapchain_ops = &swapchain_gdi_ops; break; case WINED3D_SURFACE_TYPE_OPENGL: swapchain->swapchain_ops = &swapchain_gl_ops; break; default: ERR("Invalid surface type %#x.\n", surface_type); return WINED3DERR_INVALIDCALL; } window = desc->device_window ? desc->device_window : device->create_parms.focus_window; swapchain->device = device; swapchain->parent = parent; swapchain->parent_ops = parent_ops; swapchain->ref = 1; swapchain->win_handle = window; swapchain->device_window = window; wined3d_get_adapter_display_mode(device->wined3d, adapter->ordinal, &mode); swapchain->orig_width = mode.width; swapchain->orig_height = mode.height; swapchain->orig_fmt = mode.format_id; format = wined3d_get_format(&adapter->gl_info, mode.format_id); GetClientRect(window, &client_rect); if (desc->windowed && (!desc->backbuffer_width || !desc->backbuffer_height || desc->backbuffer_format == WINED3DFMT_UNKNOWN)) { if (!desc->backbuffer_width) { desc->backbuffer_width = client_rect.right; TRACE("Updating width to %u.\n", desc->backbuffer_width); } if (!desc->backbuffer_height) { desc->backbuffer_height = client_rect.bottom; TRACE("Updating height to %u.\n", desc->backbuffer_height); } if (desc->backbuffer_format == WINED3DFMT_UNKNOWN) { desc->backbuffer_format = swapchain->orig_fmt; TRACE("Updating format to %s.\n", debug_d3dformat(swapchain->orig_fmt)); } } swapchain->desc = *desc; swapchain_update_render_to_fbo(swapchain); TRACE("Creating front buffer.\n"); hr = device->device_parent->ops->create_rendertarget(device->device_parent, parent, swapchain->desc.backbuffer_width, swapchain->desc.backbuffer_height, swapchain->desc.backbuffer_format, swapchain->desc.multisample_type, swapchain->desc.multisample_quality, TRUE /* Lockable */, &swapchain->front_buffer); if (FAILED(hr)) { WARN("Failed to create front buffer, hr %#x.\n", hr); goto err; } surface_set_container(swapchain->front_buffer, WINED3D_CONTAINER_SWAPCHAIN, swapchain); if (surface_type == WINED3D_SURFACE_TYPE_OPENGL) surface_modify_location(swapchain->front_buffer, 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 (!desc->windowed) { struct wined3d_display_mode mode; /* Change the display settings */ mode.width = desc->backbuffer_width; mode.height = desc->backbuffer_height; mode.format_id = desc->backbuffer_format; mode.refresh_rate = desc->refresh_rate; hr = wined3d_device_set_display_mode(device, 0, &mode); if (FAILED(hr)) { WARN("Failed to set display mode, hr %#x.\n", hr); goto err; } displaymode_set = TRUE; } if (surface_type == WINED3D_SURFACE_TYPE_OPENGL) { static const enum wined3d_format_id formats[] = { WINED3DFMT_D24_UNORM_S8_UINT, WINED3DFMT_D32_UNORM, WINED3DFMT_R24_UNORM_X8_TYPELESS, WINED3DFMT_D16_UNORM, WINED3DFMT_S1_UINT_D15_UNORM }; const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; 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; /* 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. */ for (i = 0; i < (sizeof(formats) / sizeof(*formats)); i++) { swapchain->ds_format = wined3d_get_format(gl_info, formats[i]); swapchain->context[0] = context_create(swapchain, swapchain->front_buffer, swapchain->ds_format); if (swapchain->context[0]) break; TRACE("Depth stencil format %s is not supported, trying next format\n", debug_d3dformat(formats[i])); } if (!swapchain->context[0]) { WARN("Failed to create context.\n"); hr = WINED3DERR_NOTAVAILABLE; goto err; } if (wined3d_settings.offscreen_rendering_mode != ORM_FBO && (!desc->enable_auto_depth_stencil || swapchain->desc.auto_depth_stencil_format != swapchain->ds_format->id)) { FIXME("Add OpenGL context recreation support to context_validate_onscreen_formats\n"); } context_release(swapchain->context[0]); } if (swapchain->desc.backbuffer_count > 0) { swapchain->back_buffers = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->back_buffers) * swapchain->desc.backbuffer_count); if (!swapchain->back_buffers) { ERR("Failed to allocate backbuffer array memory.\n"); hr = E_OUTOFMEMORY; goto err; } for (i = 0; i < swapchain->desc.backbuffer_count; ++i) { TRACE("Creating back buffer %u.\n", i); hr = device->device_parent->ops->create_rendertarget(device->device_parent, parent, swapchain->desc.backbuffer_width, swapchain->desc.backbuffer_height, swapchain->desc.backbuffer_format, swapchain->desc.multisample_type, swapchain->desc.multisample_quality, TRUE /* Lockable */, &swapchain->back_buffers[i]); if (FAILED(hr)) { WARN("Failed to create back buffer %u, hr %#x.\n", i, hr); goto err; } surface_set_container(swapchain->back_buffers[i], WINED3D_CONTAINER_SWAPCHAIN, swapchain); } } /* Swapchains share the depth/stencil buffer, so only create a single depthstencil surface. */ if (desc->enable_auto_depth_stencil && surface_type == WINED3D_SURFACE_TYPE_OPENGL) { TRACE("Creating depth/stencil buffer.\n"); if (!device->auto_depth_stencil) { hr = device->device_parent->ops->create_depth_stencil(device->device_parent, swapchain->desc.backbuffer_width, swapchain->desc.backbuffer_height, swapchain->desc.auto_depth_stencil_format, swapchain->desc.multisample_type, swapchain->desc.multisample_quality, FALSE /* FIXME: Discard */, &device->auto_depth_stencil); if (FAILED(hr)) { WARN("Failed to create the auto depth stencil, hr %#x.\n", hr); goto err; } surface_set_container(device->auto_depth_stencil, WINED3D_CONTAINER_NONE, NULL); } } wined3d_swapchain_get_gamma_ramp(swapchain, &swapchain->orig_gamma); 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->byte_count * CHAR_BIT; devmode.dmPelsWidth = swapchain->orig_width; devmode.dmPelsHeight = swapchain->orig_height; ChangeDisplaySettingsExW(adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL); } if (swapchain->back_buffers) { for (i = 0; i < swapchain->desc.backbuffer_count; ++i) { if (swapchain->back_buffers[i]) { surface_set_container(swapchain->back_buffers[i], WINED3D_CONTAINER_NONE, NULL); wined3d_surface_decref(swapchain->back_buffers[i]); } } HeapFree(GetProcessHeap(), 0, swapchain->back_buffers); } 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); } if (swapchain->front_buffer) { surface_set_container(swapchain->front_buffer, WINED3D_CONTAINER_NONE, NULL); wined3d_surface_decref(swapchain->front_buffer); } return hr; }
static HRESULT wined3d_texture_init(struct wined3d_texture *texture, const struct wined3d_texture_ops *texture_ops, UINT layer_count, UINT level_count, const struct wined3d_resource_desc *desc, struct wined3d_device *device, void *parent, const struct wined3d_parent_ops *parent_ops, const struct wined3d_resource_ops *resource_ops) { const struct wined3d_format *format = wined3d_get_format(&device->adapter->gl_info, desc->format); HRESULT hr; TRACE("texture %p, texture_ops %p, layer_count %u, level_count %u, resource_type %s, format %s, " "multisample_type %#x, multisample_quality %#x, usage %s, pool %s, width %u, height %u, depth %u, " "device %p, parent %p, parent_ops %p, resource_ops %p.\n", texture, texture_ops, layer_count, level_count, debug_d3dresourcetype(desc->resource_type), debug_d3dformat(desc->format), desc->multisample_type, desc->multisample_quality, debug_d3dusage(desc->usage), debug_d3dpool(desc->pool), desc->width, desc->height, desc->depth, device, parent, parent_ops, resource_ops); if ((format->flags & (WINED3DFMT_FLAG_BLOCKS | WINED3DFMT_FLAG_BLOCKS_NO_VERIFY)) == WINED3DFMT_FLAG_BLOCKS) { UINT width_mask = format->block_width - 1; UINT height_mask = format->block_height - 1; if (desc->width & width_mask || desc->height & height_mask) return WINED3DERR_INVALIDCALL; } if (FAILED(hr = resource_init(&texture->resource, device, desc->resource_type, format, desc->multisample_type, desc->multisample_quality, desc->usage, desc->pool, desc->width, desc->height, desc->depth, 0, parent, parent_ops, resource_ops))) { static unsigned int once; if ((desc->format == WINED3DFMT_DXT1 || desc->format == WINED3DFMT_DXT2 || desc->format == WINED3DFMT_DXT3 || desc->format == WINED3DFMT_DXT4 || desc->format == WINED3DFMT_DXT5) && !(format->flags & WINED3DFMT_FLAG_TEXTURE) && !once++) ERR_(winediag)("The application tried to create a DXTn texture, but the driver does not support them.\n"); WARN("Failed to initialize resource, returning %#x\n", hr); return hr; } wined3d_resource_update_draw_binding(&texture->resource); texture->texture_ops = texture_ops; texture->sub_resources = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, level_count * layer_count * sizeof(*texture->sub_resources)); if (!texture->sub_resources) { ERR("Failed to allocate sub-resource array.\n"); resource_cleanup(&texture->resource); return E_OUTOFMEMORY; } texture->layer_count = layer_count; texture->level_count = level_count; texture->filter_type = (desc->usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3D_TEXF_LINEAR : WINED3D_TEXF_NONE; texture->lod = 0; texture->flags = WINED3D_TEXTURE_POW2_MAT_IDENT; if (texture->resource.format->flags & WINED3DFMT_FLAG_FILTERING) { texture->min_mip_lookup = minMipLookup; texture->mag_lookup = magLookup; } else { texture->min_mip_lookup = minMipLookup_noFilter; texture->mag_lookup = magLookup_noFilter; } return WINED3D_OK; }