diff options
Diffstat (limited to 'src/intel_memory.c')
-rw-r--r-- | src/intel_memory.c | 282 |
1 files changed, 282 insertions, 0 deletions
diff --git a/src/intel_memory.c b/src/intel_memory.c new file mode 100644 index 00000000..a3d67b47 --- /dev/null +++ b/src/intel_memory.c @@ -0,0 +1,282 @@ +/************************************************************************** + +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 (IS_I965G(intel)) { + /* The 965 can have fences at any page boundary. */ + return ALIGN(size, GTT_PAGE_SIZE); + } else { + /* Align the size to a power of two greater than the smallest fence + * size. + */ + if (IS_I9XX(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 (IS_I965G(intel)) + return ROUND_TO(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 ((IS_845G(intel) || IS_I85X(intel)) && tiling) + limit = KB(8); + + if (IS_I915(intel) && tiling) + limit = KB(8); + + if (IS_I965G(intel) && tiling) + limit = KB(16); + + if (IS_IGDNG(intel) && tiling) + 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 (width + 63) & ~63; +} + +/** + * 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) +{ + intel_screen_private *intel = intel_get_screen_private(scrn); + drm_intel_bo *front_buffer; + uint32_t tiling_mode; + unsigned long pitch; + + if (intel->tiling) + tiling_mode = I915_TILING_X; + else + tiling_mode = I915_TILING_NONE; + + width = intel_pad_drawable_width(width); + + front_buffer = drm_intel_bo_alloc_tiled(intel->bufmgr, "front buffer", + width, height, intel->cpp, + &tiling_mode, &pitch, 0); + if (front_buffer == NULL) { + xf86DrvMsg(scrn->scrnIndex, X_ERROR, + "Failed to allocate framebuffer.\n"); + return NULL; + } + + if (!intel_check_display_stride(scrn, pitch, + tiling_mode != I915_TILING_NONE)) { + xf86DrvMsg(scrn->scrnIndex, X_ERROR, + "Front buffer stride %ld kB " + "exceeds display limit\n", pitch / 1024); + drm_intel_bo_unreference(front_buffer); + return NULL; + } + + if (intel->tiling && tiling_mode != I915_TILING_X) { + xf86DrvMsg(scrn->scrnIndex, X_ERROR, + "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; + + return front_buffer; +} + +static void intel_set_max_bo_size(intel_screen_private *intel, + const struct drm_i915_gem_get_aperture *aperture) +{ + if (aperture->aper_available_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 = aperture->aper_available_size / 2; + else + intel->max_bo_size = 64 * 1024 * 1024; +} + +static void intel_set_max_gtt_map_size(intel_screen_private *intel, + const struct drm_i915_gem_get_aperture *aperture) +{ + if (aperture->aper_available_size) + /* Let objects up get bound up to the size where only 2 would fit in + * the aperture, but then leave slop to account for alignment like + * libdrm does. + */ + intel->max_gtt_map_size = + aperture->aper_available_size * 3 / 4 / 2; + else + intel->max_gtt_map_size = 16 * 1024 * 1024; +} + +static void intel_set_max_tiling_size(intel_screen_private *intel, + const struct drm_i915_gem_get_aperture *aperture) +{ + if (aperture->aper_available_size) + /* Let objects be tiled up to the size where only 4 would fit in + * the aperture, presuming worst case alignment. + */ + intel->max_tiling_size = aperture->aper_available_size / 4; + else + intel->max_tiling_size = 4 * 1024 * 1024; +} + +void intel_set_gem_max_sizes(ScrnInfoPtr scrn) +{ + intel_screen_private *intel = intel_get_screen_private(scrn); + struct drm_i915_gem_get_aperture aperture; + + aperture.aper_available_size = 0; + ioctl(intel->drmSubFD, DRM_IOCTL_I915_GEM_GET_APERTURE, &aperture); + + intel_set_max_bo_size(intel, &aperture); + intel_set_max_gtt_map_size(intel, &aperture); + intel_set_max_tiling_size(intel, &aperture); +} |