diff options
Diffstat (limited to 'src/intel_memory.c')
-rw-r--r-- | src/intel_memory.c | 286 |
1 files changed, 286 insertions, 0 deletions
diff --git a/src/intel_memory.c b/src/intel_memory.c new file mode 100644 index 000000000..f08ebdd01 --- /dev/null +++ b/src/intel_memory.c @@ -0,0 +1,286 @@ +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +Copyright © 2002 by David Dawes. + +All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sub license, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND/OR THEIR SUPPLIERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ + +/* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + * David Dawes <dawes@xfree86.org> + * + * Updated for Dual Head capabilities: + * Alan Hourihane <alanh@tungstengraphics.com> + */ + +/** + * @file intel_memory.c + * + * This is the video memory allocator. Our memory allocation is different from + * other graphics chips, where you have a fixed amount of graphics memory + * available that you want to put to the best use. Instead, we have almost no + * memory pre-allocated, and we have to choose an appropriate amount of sytem + * memory to use. + * + * The allocations we might do: + * + * - Ring buffer + * - HW cursor block (either one block or four) + * - Overlay registers + * - Front buffer (screen 1) + * - Front buffer (screen 2, only in zaphod mode) + * - Back/depth buffer (3D only) + * - Compatibility texture pool (optional, more is always better) + * - New texture pool (optional, more is always better. aperture allocation + * only) + * + * The user may request a specific amount of memory to be used + * (intel->pEnt->videoRam != 0), in which case allocations have to fit within + * that much aperture. If not, the individual allocations will be + * automatically sized, and will be fit within the maximum aperture size. + * Only the actual memory used (not alignment padding) will get actual AGP + * memory allocated. + * + * Given that the allocations listed are generally a page or more than a page, + * our allocator will only return page-aligned offsets, simplifying the memory + * binding process. For smaller allocations, the acceleration architecture's + * linear allocator is preferred. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <inttypes.h> +#include <string.h> +#include <sys/types.h> +#include <sys/ioctl.h> + +#include "xf86.h" +#include "xf86_OSproc.h" + +#include "intel.h" +#include "i915_drm.h" + +/** + * Returns the fence size for a tiled area of the given size. + */ +unsigned long intel_get_fence_size(intel_screen_private *intel, unsigned long size) +{ + unsigned long i; + unsigned long start; + + if (INTEL_INFO(intel)->gen >= 40 || intel->has_relaxed_fencing) { + /* The 965 can have fences at any page boundary. */ + return ALIGN(size, 4096); + } else { + /* Align the size to a power of two greater than the smallest fence + * size. + */ + if (IS_GEN3(intel)) + start = MB(1); + else + start = KB(512); + + for (i = start; i < size; i <<= 1) ; + + return i; + } +} + +/** + * On some chips, pitch width has to be a power of two tile width, so + * calculate that here. + */ +unsigned long +intel_get_fence_pitch(intel_screen_private *intel, unsigned long pitch, + uint32_t tiling_mode) +{ + unsigned long i; + unsigned long tile_width = (tiling_mode == I915_TILING_Y) ? 128 : 512; + + if (tiling_mode == I915_TILING_NONE) + return pitch; + + /* 965+ is flexible */ + if (INTEL_INFO(intel)->gen >= 40) + return ALIGN(pitch, tile_width); + + /* Pre-965 needs power of two tile width */ + for (i = tile_width; i < pitch; i <<= 1) ; + + return i; +} + +static Bool +intel_check_display_stride(ScrnInfoPtr scrn, int stride, Bool tiling) +{ + intel_screen_private *intel = intel_get_screen_private(scrn); + int limit = KB(32); + + /* 8xx spec has always 8K limit, but tests show larger limit in + non-tiling mode, which makes large monitor work. */ + if (tiling) { + if (IS_GEN2(intel)) + limit = KB(8); + else if (IS_GEN3(intel)) + limit = KB(8); + else if (IS_GEN4(intel)) + limit = KB(16); + else + limit = KB(32); + } + + if (stride <= limit) + return TRUE; + else + return FALSE; +} + +/* + * Pad to accelerator requirement + */ +static inline int intel_pad_drawable_width(int width) +{ + return ALIGN(width, 64); +} + + +static size_t +agp_aperture_size(struct pci_device *dev, int gen) +{ + return dev->regions[gen < 30 ? 0 : 2].size; +} + +static void intel_set_gem_max_sizes(ScrnInfoPtr scrn) +{ + intel_screen_private *intel = intel_get_screen_private(scrn); + size_t agp_size = agp_aperture_size(intel->PciInfo, + INTEL_INFO(intel)->gen); + + /* The chances of being able to mmap an object larger than + * agp_size/2 are slim. Moreover, we may be forced to fallback + * using a gtt mapping as both the source and a mask, as well + * as a destination and all need to fit into the aperture. + */ + intel->max_gtt_map_size = agp_size / 4; + + /* Let objects be tiled up to the size where only 4 would fit in + * the aperture, presuming best case alignment. Also if we + * cannot mmap it using the GTT we will be stuck. */ + intel->max_tiling_size = intel->max_gtt_map_size; + + /* Large BOs will tend to hit SW fallbacks frequently, and also will + * tend to fail to successfully map when doing SW fallbacks because we + * overcommit address space for BO access, or worse cause aperture + * thrashing. + */ + intel->max_bo_size = intel->max_gtt_map_size; +} + +/** + * Allocates a framebuffer for a screen. + * + * Used once for each X screen, so once with RandR 1.2 and twice with classic + * dualhead. + */ +drm_intel_bo *intel_allocate_framebuffer(ScrnInfoPtr scrn, + int width, int height, int cpp, + unsigned long *out_pitch, + uint32_t *out_tiling) +{ + intel_screen_private *intel = intel_get_screen_private(scrn); + drm_intel_bo *front_buffer; + uint32_t tiling_mode; + unsigned long pitch; + + if (intel->tiling & INTEL_TILING_FB) + tiling_mode = I915_TILING_X; + else + tiling_mode = I915_TILING_NONE; + + width = intel_pad_drawable_width(width); + if (!intel_check_display_stride(scrn, width * intel->cpp, + tiling_mode != I915_TILING_NONE)) + tiling_mode = I915_TILING_NONE; + if (!intel_check_display_stride(scrn, width * intel->cpp, + tiling_mode != I915_TILING_NONE)) { + xf86DrvMsg(scrn->scrnIndex, X_ERROR, + "Expected front buffer stride %d kB " + "will exceed display limit\n", + width * intel->cpp / 1024); + return NULL; + } + +retry: + front_buffer = drm_intel_bo_alloc_tiled(intel->bufmgr, "front buffer", + width, height, intel->cpp, + &tiling_mode, &pitch, 0); + if (front_buffer == NULL) { + if (tiling_mode != I915_TILING_NONE) { + tiling_mode = I915_TILING_NONE; + goto retry; + } + xf86DrvMsg(scrn->scrnIndex, X_ERROR, + "Failed to allocate framebuffer.\n"); + return NULL; + } + + if (!intel_check_display_stride(scrn, pitch, + tiling_mode != I915_TILING_NONE)) { + drm_intel_bo_unreference(front_buffer); + if (tiling_mode != I915_TILING_NONE) { + tiling_mode = I915_TILING_NONE; + goto retry; + } + + xf86DrvMsg(scrn->scrnIndex, X_ERROR, + "Front buffer stride %ld kB " + "exceeds display limit\n", pitch / 1024); + return NULL; + } + + /* If we could have used tiling but failed, warn */ + if (intel->tiling & INTEL_TILING_FB && + tiling_mode != I915_TILING_X && + intel_check_display_stride(scrn, pitch, I915_TILING_X)) + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "Failed to set tiling on frontbuffer.\n"); + + xf86DrvMsg(scrn->scrnIndex, X_INFO, + "Allocated new frame buffer %dx%d stride %ld, %s\n", + width, height, pitch, + tiling_mode == I915_TILING_NONE ? "untiled" : "tiled"); + + drm_intel_bo_disable_reuse(front_buffer); + + intel_set_gem_max_sizes(scrn); + *out_pitch = pitch; + *out_tiling = tiling_mode; + + return front_buffer; +} |