radeon_state.c

来自「linux 内核源代码」· C语言 代码 · 共 2,223 行 · 第 1/5 页

C
2,223
字号
		if (microtile) {			/* texture micro tiling in use, minimum texture width is thus 16 bytes.			   however, we cannot use blitter directly for texture width < 64 bytes,			   since minimum tex pitch is 64 bytes and we need this to match			   the texture width, otherwise the blitter will tile it wrong.			   Thus, tiling manually in this case. Additionally, need to special			   case tex height = 1, since our actual image will have height 2			   and we need to ensure we don't read beyond the texture size			   from user space. */			if (tex->height == 1) {				if (tex_width >= 64 || tex_width <= 16) {					RADEON_COPY_MT(buffer, data,						(int)(tex_width * sizeof(u32)));				} else if (tex_width == 32) {					RADEON_COPY_MT(buffer, data, 16);					RADEON_COPY_MT(buffer + 8,						       data + 16, 16);				}			} else if (tex_width >= 64 || tex_width == 16) {				RADEON_COPY_MT(buffer, data,					       (int)(dwords * sizeof(u32)));			} else if (tex_width < 16) {				for (i = 0; i < tex->height; i++) {					RADEON_COPY_MT(buffer, data, tex_width);					buffer += 4;					data += tex_width;				}			} else if (tex_width == 32) {				/* TODO: make sure this works when not fitting in one buffer				   (i.e. 32bytes x 2048...) */				for (i = 0; i < tex->height; i += 2) {					RADEON_COPY_MT(buffer, data, 16);					data += 16;					RADEON_COPY_MT(buffer + 8, data, 16);					data += 16;					RADEON_COPY_MT(buffer + 4, data, 16);					data += 16;					RADEON_COPY_MT(buffer + 12, data, 16);					data += 16;					buffer += 16;				}			}		} else {			if (tex_width >= 32) {				/* Texture image width is larger than the minimum, so we				 * can upload it directly.				 */				RADEON_COPY_MT(buffer, data,					       (int)(dwords * sizeof(u32)));			} else {				/* Texture image width is less than the minimum, so we				 * need to pad out each image scanline to the minimum				 * width.				 */				for (i = 0; i < tex->height; i++) {					RADEON_COPY_MT(buffer, data, tex_width);					buffer += 8;					data += tex_width;				}			}		}#undef RADEON_COPY_MT		buf->file_priv = file_priv;		buf->used = size;		offset = dev_priv->gart_buffers_offset + buf->offset;		BEGIN_RING(9);		OUT_RING(CP_PACKET3(RADEON_CNTL_BITBLT_MULTI, 5));		OUT_RING(RADEON_GMC_SRC_PITCH_OFFSET_CNTL |			 RADEON_GMC_DST_PITCH_OFFSET_CNTL |			 RADEON_GMC_BRUSH_NONE |			 (format << 8) |			 RADEON_GMC_SRC_DATATYPE_COLOR |			 RADEON_ROP3_S |			 RADEON_DP_SRC_SOURCE_MEMORY |			 RADEON_GMC_CLR_CMP_CNTL_DIS | RADEON_GMC_WR_MSK_DIS);		OUT_RING((spitch << 22) | (offset >> 10));		OUT_RING((texpitch << 22) | (tex->offset >> 10));		OUT_RING(0);		OUT_RING((image->x << 16) | image->y);		OUT_RING((image->width << 16) | height);		RADEON_WAIT_UNTIL_2D_IDLE();		ADVANCE_RING();		COMMIT_RING();		radeon_cp_discard_buffer(dev, buf);		/* Update the input parameters for next time */		image->y += height;		image->height -= height;		image->data = (const u8 __user *)image->data + size;	} while (image->height > 0);	/* Flush the pixel cache after the blit completes.  This ensures	 * the texture data is written out to memory before rendering	 * continues.	 */	BEGIN_RING(4);	RADEON_FLUSH_CACHE();	RADEON_WAIT_UNTIL_2D_IDLE();	ADVANCE_RING();	COMMIT_RING();	return 0;}static void radeon_cp_dispatch_stipple(struct drm_device * dev, u32 * stipple){	drm_radeon_private_t *dev_priv = dev->dev_private;	int i;	RING_LOCALS;	DRM_DEBUG("\n");	BEGIN_RING(35);	OUT_RING(CP_PACKET0(RADEON_RE_STIPPLE_ADDR, 0));	OUT_RING(0x00000000);	OUT_RING(CP_PACKET0_TABLE(RADEON_RE_STIPPLE_DATA, 31));	for (i = 0; i < 32; i++) {		OUT_RING(stipple[i]);	}	ADVANCE_RING();}static void radeon_apply_surface_regs(int surf_index,				      drm_radeon_private_t *dev_priv){	if (!dev_priv->mmio)		return;	radeon_do_cp_idle(dev_priv);	RADEON_WRITE(RADEON_SURFACE0_INFO + 16 * surf_index,		     dev_priv->surfaces[surf_index].flags);	RADEON_WRITE(RADEON_SURFACE0_LOWER_BOUND + 16 * surf_index,		     dev_priv->surfaces[surf_index].lower);	RADEON_WRITE(RADEON_SURFACE0_UPPER_BOUND + 16 * surf_index,		     dev_priv->surfaces[surf_index].upper);}/* Allocates a virtual surface * doesn't always allocate a real surface, will stretch an existing * surface when possible. * * Note that refcount can be at most 2, since during a free refcount=3 * might mean we have to allocate a new surface which might not always * be available. * For example : we allocate three contigous surfaces ABC. If B is * freed, we suddenly need two surfaces to store A and C, which might * not always be available. */static int alloc_surface(drm_radeon_surface_alloc_t *new,			 drm_radeon_private_t *dev_priv,			 struct drm_file *file_priv){	struct radeon_virt_surface *s;	int i;	int virt_surface_index;	uint32_t new_upper, new_lower;	new_lower = new->address;	new_upper = new_lower + new->size - 1;	/* sanity check */	if ((new_lower >= new_upper) || (new->flags == 0) || (new->size == 0) ||	    ((new_upper & RADEON_SURF_ADDRESS_FIXED_MASK) !=	     RADEON_SURF_ADDRESS_FIXED_MASK)	    || ((new_lower & RADEON_SURF_ADDRESS_FIXED_MASK) != 0))		return -1;	/* make sure there is no overlap with existing surfaces */	for (i = 0; i < RADEON_MAX_SURFACES; i++) {		if ((dev_priv->surfaces[i].refcount != 0) &&		    (((new_lower >= dev_priv->surfaces[i].lower) &&		      (new_lower < dev_priv->surfaces[i].upper)) ||		     ((new_lower < dev_priv->surfaces[i].lower) &&		      (new_upper > dev_priv->surfaces[i].lower)))) {			return -1;		}	}	/* find a virtual surface */	for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++)		if (dev_priv->virt_surfaces[i].file_priv == 0)			break;	if (i == 2 * RADEON_MAX_SURFACES) {		return -1;	}	virt_surface_index = i;	/* try to reuse an existing surface */	for (i = 0; i < RADEON_MAX_SURFACES; i++) {		/* extend before */		if ((dev_priv->surfaces[i].refcount == 1) &&		    (new->flags == dev_priv->surfaces[i].flags) &&		    (new_upper + 1 == dev_priv->surfaces[i].lower)) {			s = &(dev_priv->virt_surfaces[virt_surface_index]);			s->surface_index = i;			s->lower = new_lower;			s->upper = new_upper;			s->flags = new->flags;			s->file_priv = file_priv;			dev_priv->surfaces[i].refcount++;			dev_priv->surfaces[i].lower = s->lower;			radeon_apply_surface_regs(s->surface_index, dev_priv);			return virt_surface_index;		}		/* extend after */		if ((dev_priv->surfaces[i].refcount == 1) &&		    (new->flags == dev_priv->surfaces[i].flags) &&		    (new_lower == dev_priv->surfaces[i].upper + 1)) {			s = &(dev_priv->virt_surfaces[virt_surface_index]);			s->surface_index = i;			s->lower = new_lower;			s->upper = new_upper;			s->flags = new->flags;			s->file_priv = file_priv;			dev_priv->surfaces[i].refcount++;			dev_priv->surfaces[i].upper = s->upper;			radeon_apply_surface_regs(s->surface_index, dev_priv);			return virt_surface_index;		}	}	/* okay, we need a new one */	for (i = 0; i < RADEON_MAX_SURFACES; i++) {		if (dev_priv->surfaces[i].refcount == 0) {			s = &(dev_priv->virt_surfaces[virt_surface_index]);			s->surface_index = i;			s->lower = new_lower;			s->upper = new_upper;			s->flags = new->flags;			s->file_priv = file_priv;			dev_priv->surfaces[i].refcount = 1;			dev_priv->surfaces[i].lower = s->lower;			dev_priv->surfaces[i].upper = s->upper;			dev_priv->surfaces[i].flags = s->flags;			radeon_apply_surface_regs(s->surface_index, dev_priv);			return virt_surface_index;		}	}	/* we didn't find anything */	return -1;}static int free_surface(struct drm_file *file_priv,			drm_radeon_private_t * dev_priv,			int lower){	struct radeon_virt_surface *s;	int i;	/* find the virtual surface */	for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++) {		s = &(dev_priv->virt_surfaces[i]);		if (s->file_priv) {			if ((lower == s->lower) && (file_priv == s->file_priv))			{				if (dev_priv->surfaces[s->surface_index].				    lower == s->lower)					dev_priv->surfaces[s->surface_index].					    lower = s->upper;				if (dev_priv->surfaces[s->surface_index].				    upper == s->upper)					dev_priv->surfaces[s->surface_index].					    upper = s->lower;				dev_priv->surfaces[s->surface_index].refcount--;				if (dev_priv->surfaces[s->surface_index].				    refcount == 0)					dev_priv->surfaces[s->surface_index].					    flags = 0;				s->file_priv = NULL;				radeon_apply_surface_regs(s->surface_index,							  dev_priv);				return 0;			}		}	}	return 1;}static void radeon_surfaces_release(struct drm_file *file_priv,				    drm_radeon_private_t * dev_priv){	int i;	for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++) {		if (dev_priv->virt_surfaces[i].file_priv == file_priv)			free_surface(file_priv, dev_priv,				     dev_priv->virt_surfaces[i].lower);	}}/* ================================================================ * IOCTL functions */static int radeon_surface_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv){	drm_radeon_private_t *dev_priv = dev->dev_private;	drm_radeon_surface_alloc_t *alloc = data;	if (alloc_surface(alloc, dev_priv, file_priv) == -1)		return -EINVAL;	else		return 0;}static int radeon_surface_free(struct drm_device *dev, void *data, struct drm_file *file_priv){	drm_radeon_private_t *dev_priv = dev->dev_private;	drm_radeon_surface_free_t *memfree = data;	if (free_surface(file_priv, dev_priv, memfree->address))		return -EINVAL;	else		return 0;}static int radeon_cp_clear(struct drm_device *dev, void *data, struct drm_file *file_priv){	drm_radeon_private_t *dev_priv = dev->dev_private;	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;	drm_radeon_clear_t *clear = data;	drm_radeon_clear_rect_t depth_boxes[RADEON_NR_SAREA_CLIPRECTS];	DRM_DEBUG("\n");	LOCK_TEST_WITH_RETURN(dev, file_priv);	RING_SPACE_TEST_WITH_RETURN(dev_priv);	if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS)		sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS;	if (DRM_COPY_FROM_USER(&depth_boxes, clear->depth_boxes,			       sarea_priv->nbox * sizeof(depth_boxes[0])))		return -EFAULT;	radeon_cp_dispatch_clear(dev, clear, depth_boxes);	COMMIT_RING();	return 0;}/* Not sure why this isn't set all the time: */static int radeon_do_init_pageflip(struct drm_device * dev){	drm_radeon_private_t *dev_priv = dev->dev_private;	RING_LOCALS;	DRM_DEBUG("\n");	BEGIN_RING(6);	RADEON_WAIT_UNTIL_3D_IDLE();	OUT_RING(CP_PACKET0(RADEON_CRTC_OFFSET_CNTL, 0));	OUT_RING(RADEON_READ(RADEON_CRTC_OFFSET_CNTL) |		 RADEON_CRTC_OFFSET_FLIP_CNTL);	OUT_RING(CP_PACKET0(RADEON_CRTC2_OFFSET_CNTL, 0));	OUT_RING(RADEON_READ(RADEON_CRTC2_OFFSET_CNTL) |		 RADEON_CRTC_OFFSET_FLIP_CNTL);	ADVANCE_RING();	dev_priv->page_flipping = 1;	if (dev_priv->sarea_priv->pfCurrentPage != 1)		dev_priv->sarea_priv->pfCurrentPage = 0;	return 0;}/* Swapping and flipping are different operations, need different ioctls. * They can & should be intermixed to support multiple 3d windows. */static int radeon_cp_flip(struct drm_device *dev, void *data, struct drm_file *file_priv){	drm_radeon_private_t *dev_priv = dev->dev_private;	DRM_DEBUG("\n");	LOCK_TEST_WITH_RETURN(dev, file_priv);	RING_SPACE_TEST_WITH_RETURN(dev_priv);	if (!dev_priv->page_flipping)		radeon_do_init_pageflip(dev);	radeon_cp_dispatch_flip(dev);	COMMIT_RING();	return 0;}static int radeon_cp_swap(struct drm_device *dev, void *data, struct drm_file *file_priv){	drm_radeon_private_t *dev_priv = dev->dev_private;	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;	DRM_DEBUG("\n");	LOCK_TEST_WITH_RETURN(dev, file_priv);	RING_SPACE_TEST_WITH_RETURN(dev_priv);	if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS)		sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS;	radeon_cp_dispatch_swap(dev);	dev_priv->sarea_priv->ctx_owner = 0;	COMMIT_RING();	return 0;}static int radeon_cp_vertex(struct drm_device *dev, void *data, struct drm_file *file_priv){	drm_radeon_private_t *dev_priv = dev->dev_private;	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;	struct drm_device_dma *dma = dev->dma;	struct drm_buf *buf;	drm_radeon_vertex_t *vertex = data;	drm_radeon_tcl_prim_t prim;	LOCK_TEST_WITH_RETURN(dev, file_priv);	DRM_DEBUG("pid=%d index=%d count=%d discard=%d\n",		  DRM_CURRENTPID, vertex->idx, vertex->count, vertex->discard);	if (vertex->idx < 0 || vertex->idx >= dma->buf_count) {		DRM_ERROR("buffer index %d (of %d max)\n",			  vertex->idx, dma->buf_count - 1);		return -EINVAL;	}	if (vertex->prim < 0 || vertex->prim > RADEON_PRIM_TYPE_3VRT_LINE_LIST) {		DRM_ERROR("buffer prim %d\n", vertex->prim);		return -EINVAL;	}	RING_SPACE_TEST_WITH_RETURN(dev_priv);	VB_AGE_TEST_WITH_RETURN(dev_priv);	buf = dma->

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?