Пример #1
0
static Bool maliModifyPixmapHeader(PixmapPtr pPixmap, int width, int height, int depth, int bitsPerPixel, int devKind, pointer pPixData)
{
	unsigned int size;
	PrivPixmap *privPixmap = (PrivPixmap *)exaGetPixmapDriverPrivate(pPixmap);
	mali_mem_info *mem_info;
	ScreenPtr pScreen = pPixmap->drawable.pScreen;
	ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
	MaliPtr fPtr = MALIPTR(pScrn);

	if (!pPixmap)
	{
		return FALSE;
	}

	miModifyPixmapHeader(pPixmap, width, height, depth, bitsPerPixel, devKind, pPixData);

	if ((pPixData == fPtr->fbmem) || current_buf)
	{
		/* Wrap one of the fbdev virtual buffers */
		ump_secure_id ump_id = UMP_INVALID_SECURE_ID;

		privPixmap->isFrameBuffer = TRUE;
		privPixmap->frameBufferNumber = current_buf;
		mem_info = privPixmap->mem_info;

		if (mem_info)
		{
			return TRUE;
		}

		/* create new mem_info for the on-screen buffer */
		mem_info = calloc(1, sizeof(*mem_info));

		if (!mem_info)
		{
			ERROR_MSG("failed to allocate for memory metadata");
			return FALSE;
		}

		/* get the secure ID for the framebuffers */
		if (ioctl(fPtr->fb_lcd_fd, GET_UMP_SECURE_ID_BUF(current_buf), &ump_id) < 0
		        || UMP_INVALID_SECURE_ID == ump_id)
		{
			free(mem_info);
			privPixmap->mem_info = NULL;
			ERROR_MSG("UMP failed to retrieve secure id, current_buf: %d", current_buf);
			return FALSE;
		}

		INFO_MSG("GET_UMP_SECURE_ID_BUF(%d) returned 0x%x", current_buf, ump_id);

		mem_info->handle = ump_handle_create_from_secure_id(ump_id);

		if (UMP_INVALID_MEMORY_HANDLE == mem_info->handle)
		{
			ERROR_MSG("UMP failed to create handle from secure id");
			free(mem_info);
			privPixmap->mem_info = NULL;
			return FALSE;
		}

		size = exaGetPixmapPitch(pPixmap) * pPixmap->drawable.height;
		mem_info->usize = size;

		privPixmap->mem_info = mem_info;

		if (bitsPerPixel != 0)
		{
			privPixmap->bits_per_pixel = bitsPerPixel;
		}

		/* When this is called directly from X to create the front buffer, current_buf is zero as expected. When this
		 * function is called recursively to create the back buffers, current_buf is increased to the next buffer */
		privPixmap->mem_info->offset = current_buf * size;

		if (pPixData == fPtr->fbmem)
		{
			/* This is executed only when this function is called directly from X. We need to create the other
			 * back buffers now because we can't "wrap" existing memory in a pixmap during DRI2CreateBuffer
			 * for the back buffer of the framebuffer. In DRI2CreateBuffer instead of allocating a new
			 * pixmap for the back buffer like we do for non-swappable windows, we'll just use the 'current_pixmap'
			 * to grab this pointer from the screen pixmap and return it. */

			PrivPixmap *current_privPixmap = privPixmap;
			int i;
			PrivBuffer *buf_info = calloc(1, sizeof(*buf_info));

			if (NULL == buf_info)
			{
				ERROR_MSG("Failed to allocate buf_info memory");
				free(mem_info);
				privPixmap->mem_info = NULL;
				return FALSE;
			}

			buf_info->current_pixmap = 0;
			buf_info->num_pixmaps = fPtr->dri2_num_buffers;
			buf_info->pPixmaps[0] = pPixmap;
			current_privPixmap->buf_info = buf_info;

			for (i = 1; i < buf_info->num_pixmaps; i++)
			{
				current_buf++;
				buf_info->pPixmaps[i] = (*pScreen->CreatePixmap)(pScreen, width, height, depth, 0);
				assert(buf_info->pPixmaps[i]);
				current_privPixmap = (PrivPixmap *)exaGetPixmapDriverPrivate(buf_info->pPixmaps[i]);
				current_privPixmap->buf_info = buf_info;
			}

			current_buf = 0;
		}

		INFO_MSG("Creating FRAMEBUFFER pixmap %p at offset %lu, privPixmap=%p", pPixmap, privPixmap->mem_info->offset, privPixmap);

		return TRUE;
	}

	if (pPixData)
	{
		/* When this happens we're being told to wrap existing pixmap data for which we don't know the UMP
		 * handle. We can and still need to wrap it but it won't be offscreen - we can't accelerate it in any
		 * way. */

		if (privPixmap->mem_info != NULL)
		{
			return TRUE;
		}

		return FALSE;
	}

	pPixmap->devKind = ((pPixmap->drawable.width * pPixmap->drawable.bitsPerPixel) + 7) / 8;
	pPixmap->devKind = MALI_ALIGN(pPixmap->devKind, 8);

	size = exaGetPixmapPitch(pPixmap) * pPixmap->drawable.height;

	/* allocate pixmap data */
	mem_info = privPixmap->mem_info;

	if (mem_info && mem_info->usize == size)
	{
		return TRUE;
	}

	if (mem_info && mem_info->usize != 0)
	{
		ump_reference_release(mem_info->handle);
		mem_info->handle = NULL;
		memset(privPixmap, 0, sizeof(*privPixmap));

		return TRUE;
	}

	if (!size)
	{
		return TRUE;
	}

	if (NULL == mem_info)
	{
		mem_info = calloc(1, sizeof(*mem_info));

		if (!mem_info)
		{
			ERROR_MSG("failed to allocate memory metadata");
			return FALSE;
		}
	}

	if (fPtr->use_cached_ump)
	{
		mem_info->handle = ump_ref_drv_allocate(size, UMP_REF_DRV_CONSTRAINT_PHYSICALLY_LINEAR | UMP_REF_DRV_CONSTRAINT_USE_CACHE);
	}
	else
	{
		mem_info->handle = ump_ref_drv_allocate(size, UMP_REF_DRV_CONSTRAINT_PHYSICALLY_LINEAR);
	}

	if (UMP_INVALID_MEMORY_HANDLE == mem_info->handle)
	{
		ERROR_MSG("failed to allocate UMP memory (%i bytes)", size);
		return FALSE;
	}

	mem_info->usize = size;
	privPixmap->mem_info = mem_info;
	privPixmap->mem_info->usize = size;
	privPixmap->bits_per_pixel = 16;

	return TRUE;
}
mali_addr _mali_projob_add_pp_drawcall(struct mali_frame_builder* frame_builder, mali_addr rsw_address)
{
	mali_mem_pool* pool;
	int xoffset = 0;
	int yoffset = 0;
	float* posbuf;
	mali_addr pos_addr = 0;
	mali_addr out_addr = 0;
	
	struct mali_projob* projob;
	mali_internal_frame* frame;

	MALI_DEBUG_ASSERT_POINTER(frame_builder);

	frame = GET_CURRENT_INTERNAL_FRAME(frame_builder);

	MALI_DEBUG_ASSERT_POINTER(frame);

	projob = &frame->projob;

	MALI_DEBUG_ASSERT(frame->state == FRAME_DIRTY, ("Current frame must be in the DIRTY state"));

	if(projob->sync_handle == NULL) 
	{
		/* create a new sync handle at the first projob drawcall in a frame 
		 * This sync handle persists until flush() or reset() is called */
		projob->sync_handle = _mali_sync_handle_new(frame_builder->base_ctx);
		if(projob->sync_handle == NULL) return 0;
	}

	pool = _mali_frame_builder_frame_pool_get( frame_builder);

	/* If there is no current job or no more space in the current job, 
	 * reallocate room for a new HW job, and a new HW job */
	if(projob->num_pp_drawcalls_added_to_the_current_pp_job >= PROJOB_DRAWCALL_LIMIT ||
	   projob->projob_pp_job_array == NULL ) /* no current job */
	{
		mali_err_code err = allocate_and_setup_pp_job(projob, pool, frame_builder, frame);
		if(err != MALI_ERR_NO_ERROR) return 0;
	}
	   
	/* figure out where the new drawcall should reside, based on num_drawcalls_added 
	 * The current code assumes a 16*16 tile, all drawcalls are added in order. 
	 * The output address for a projob is on the output buffer, offseted for pixel coord.*/
	xoffset = projob->num_pp_drawcalls_added_to_the_current_pp_job % PROJOB_DRAWCALL_WIDTH;
	yoffset = projob->num_pp_drawcalls_added_to_the_current_pp_job / PROJOB_DRAWCALL_WIDTH;
	MALI_DEBUG_ASSERT(xoffset < PROJOB_DRAWCALL_WIDTH, ("Projob pixel must be inside the screen"));
	MALI_DEBUG_ASSERT(yoffset < PROJOB_DRAWCALL_HEIGHT, ("Projob pixel must be inside the screen"));

	out_addr = (projob->output_mali_addr) + 
	           (MALI_ALIGN(PROJOB_DRAWCALL_WIDTH, MALI200_TILE_SIZE) * 4 * sizeof(u16) * yoffset) +
	           4 * sizeof(u16) * xoffset;


	/* allocate position buffer. It need to hold 3 vertices for a standard quad, each
	 * a vec4 fp32 value. Then fill it in so that it is covering the pixel in question. */
	posbuf = _mali_mem_pool_alloc(pool, 3 * 4 * sizeof(float), &pos_addr);
	if(posbuf == NULL) return 0;

    posbuf[0] = xoffset + 1.0;
	posbuf[1] = yoffset;
	posbuf[2] = 0.0;
	posbuf[3] = 1.0;

	posbuf[4] = xoffset;
	posbuf[5] = yoffset;
	posbuf[6] = 0.0;
	posbuf[7] = 1.0;

	posbuf[8] = xoffset;
	posbuf[9] = yoffset + 1.0;
	posbuf[10] = 0.0;
	posbuf[11] = 1.0;

	/* and add this drawcall to the current job! */
	_mali200_draw_pp_job_quad( projob->mapped_pp_tilelist,
	                           &projob->mapped_pp_tilelist_byteoffset,
	                           projob->mapped_pp_tilelist_bytesize,
	                           pos_addr,
	                           rsw_address);

	projob->num_pp_drawcalls_added_to_the_current_pp_job++;


	return out_addr;
}
MALI_STATIC mali_err_code allocate_and_setup_pp_job(struct mali_projob* projob, mali_mem_pool* pool, mali_frame_builder* frame_builder, mali_internal_frame* frame)
{
	void* outbuf;
	mali_tilelist_cmd* tilebuf;
	mali_addr out_addr;
	mali_addr tile_addr;
	void* new_jobarray;
	mali_pp_job_handle new_job;
	u32 num_tilebuf_commands;

	MALI_DEBUG_ASSERT_POINTER(projob);
	MALI_DEBUG_ASSERT_POINTER(pool);
	MALI_DEBUG_ASSERT_POINTER(frame_builder);

	/* grow PP job array size by one */
	new_jobarray = _mali_sys_realloc(projob->projob_pp_job_array,
	                  sizeof(mali_pp_job_handle) * (projob->projob_pp_job_array_size + 1));
	if(new_jobarray == NULL) return MALI_ERR_OUT_OF_MEMORY;
	/* use new array regardless of future errors, but don't grow the size until we use it*/
	projob->projob_pp_job_array = new_jobarray;

	/* allocate new empty job. Will mostly be set up on flush!
	 * We allocate this now to avoid memfail issues on flush! */
	new_job = _mali_pp_job_new(frame_builder->base_ctx, 1); /* split count 1 */ 
	if(new_job == NULL) return MALI_ERR_OUT_OF_MEMORY;
	
	/* we need to set up all registers for this job. The WBx registers and the 
	 * tilelist pointers in particular. Both memory blocks must be allocated right here */

	/* allocate a new output buffer. This is allocated on the fbuilder framepool. 
	 * Need space for PROJOB_DRAWCALL_LIMIT drawcalls * vec4 * fp16 bytes outputs.
	 * The space also need to be a full tile worth of outputs, so using MALI_ALIGN
	 * to expand the limit to the next MALI200_TILE_SIZE boundary. */
	outbuf = _mali_mem_pool_alloc(pool,
	             MALI_ALIGN(PROJOB_DRAWCALL_LIMIT, MALI200_TILE_SIZE*MALI200_TILE_SIZE)
				 * 4 * sizeof(u16), &out_addr);	
	if(outbuf == NULL) 
	{
		_mali_pp_job_free(new_job);
		return MALI_ERR_OUT_OF_MEMORY;
	}

	/* allocate new tilelist buffer. This is allocated on the fbuilder framepool. 
	 * Need space for PROJOB_DRAWCALL_LIMIT * 2 commands à 8 bytes each, plus initialization
	 * commands and an end command */
	num_tilebuf_commands = PROJOB_DRAWCALL_LIMIT*2 + 2; /*+2 for "begin tile" and "end list" */
	tilebuf = _mali_mem_pool_alloc(pool,
	             num_tilebuf_commands*sizeof(mali_tilelist_cmd), &tile_addr);	
	if(tilebuf == NULL) 
	{
		_mali_pp_job_free(new_job);
		return MALI_ERR_OUT_OF_MEMORY;
	}

	/* setup registers */
	_m200_frame_reg_write_common(new_job, M200_FRAME_REG_REND_LIST_ADDR, tile_addr);
	_m200_frame_reg_write_common(new_job, M200_FRAME_REG_REND_RSW_BASE, _mali_mem_mali_addr_get( frame_builder->dummy_rsw_mem, 0));
	_m200_frame_reg_write_common(new_job, M200_FRAME_REG_FEATURE_ENABLE, M200_FEATURE_FP_TILEBUF_ENABLE );
	/* Not set: Stack addr, offsets. Currently all projobs don't use stack, so it's not needed. */
	_m200_wb_reg_write( new_job, 0, M200_WBx_REG_SOURCE_SELECT, M200_WBx_SOURCE_ARGB );
	_m200_wb_reg_write( new_job, 0, M200_WBx_REG_TARGET_ADDR, out_addr );
	_m200_wb_reg_write( new_job, 0, M200_WBx_REG_TARGET_PIXEL_FORMAT, MALI_PIXEL_FORMAT_ARGB_FP16 );
	_m200_wb_reg_write( new_job, 0, M200_WBx_REG_TARGET_LAYOUT, MALI_PIXEL_LAYOUT_LINEAR);
	_m200_wb_reg_write( new_job, 0, M200_WBx_REG_TARGET_SCANLINE_LENGTH, MALI_ALIGN(PROJOB_DRAWCALL_WIDTH, MALI200_TILE_SIZE)*sizeof(u16)*4 / 8);
	_m200_wb_reg_write( new_job, 0, M200_WBx_REG_TARGET_FLAGS, M200_WBx_TARGET_FLAGS_SWAP_RED_BLUE_ENABLE);

#if MALI_TIMELINE_PROFILING_ENABLED
	_mali_pp_job_set_identity(new_job, frame_builder->identifier | MALI_FRAME_BUILDER_TYPE_PROJOB_BIT, frame->flush_id);
#else 
	MALI_IGNORE(frame);
#endif

	/* and set this new job as the current frame */
	projob->projob_pp_job_array[projob->projob_pp_job_array_size] = new_job;
	projob->projob_pp_job_array_size++;

	projob->mapped_pp_tilelist = tilebuf;
	projob->mapped_pp_tilelist_bytesize = num_tilebuf_commands*sizeof(mali_tilelist_cmd);
	projob->mapped_pp_tilelist_byteoffset = 1*sizeof(mali_tilelist_cmd); /* adding 1 command: "begin tile" */
    projob->pp_tilelist_addr = tile_addr;
    projob->output_mali_addr = out_addr;

	projob->num_pp_drawcalls_added_to_the_current_pp_job = 0;

	/* fill in begin tile / end list commands in the tile buffer */
	MALI_PL_CMD_BEGIN_NEW_TILE( tilebuf[0], 0, 0 );
	MALI_PL_CMD_END_OF_LIST(tilebuf[1]);

	/* and set up the new job to trigger the sync handle when done */
	_mali_pp_job_add_to_sync_handle(projob->sync_handle, new_job);

	return MALI_ERR_NO_ERROR;
}
static Bool maliModifyPixmapHeader(PixmapPtr pPixmap, int width, int height, int depth, int bitsPerPixel, int devKind, pointer pPixData)
{
	unsigned int size;
	PrivPixmap *privPixmap = (PrivPixmap *)exaGetPixmapDriverPrivate(pPixmap);
	mali_mem_info *mem_info;
	ScreenPtr pScreen = pPixmap->drawable.pScreen;
	ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
	MaliPtr fPtr = MALIPTR(pScrn);

	if (!pPixmap)
	{
		return FALSE;
	}

	miModifyPixmapHeader(pPixmap, width, height, depth, bitsPerPixel, devKind, pPixData);

	if ((pPixData == fPtr->fbmem) || offset)
	{
		/* Wrap one of the fbdev virtual buffers */
		ump_secure_id ump_id = UMP_INVALID_SECURE_ID;

		privPixmap->isFrameBuffer = TRUE;

		mem_info = privPixmap->mem_info;

		if (mem_info)
		{
			return TRUE;
		}

		/* create new mem_info for the on-screen buffer */
		mem_info = calloc(1, sizeof(*mem_info));

		if (!mem_info)
		{
			ERROR_MSG("failed to allocate for memory metadata");
			return FALSE;
		}

		/* get the secure ID for the framebuffers */
		if (!offset)
		{
			(void)ioctl(fPtr->fb_lcd_fd, GET_UMP_SECURE_ID_BUF1, &ump_id);
			ERROR_MSG("GET_UMP_SECURE_ID_BUF1 returned 0x%x offset: %i virt address: %p fb_virt: %p\n", ump_id, offset, pPixData, fPtr->fbmem);
		}
		else
		{
			(void)ioctl(fPtr->fb_lcd_fd, GET_UMP_SECURE_ID_BUF2, &ump_id);
			ERROR_MSG("GET_UMP_SECURE_ID_BUF2 returned 0x%x offset: %i virt address: %p fb_virt: %p\n", ump_id, offset, pPixData, fPtr->fbmem);
		}

		if (UMP_INVALID_SECURE_ID == ump_id)
		{
			free(mem_info);
			privPixmap->mem_info = NULL;
			ERROR_MSG("UMP failed to retrieve secure id");
			return FALSE;
		}

		mem_info->handle = ump_handle_create_from_secure_id(ump_id);

		if (UMP_INVALID_MEMORY_HANDLE == mem_info->handle)
		{
			ERROR_MSG("UMP failed to create handle from secure id");
			free(mem_info);
			privPixmap->mem_info = NULL;
			return FALSE;
		}

		size = exaGetPixmapPitch(pPixmap) * pPixmap->drawable.height;
		mem_info->usize = size;

		privPixmap->mem_info = mem_info;

		if (bitsPerPixel != 0)
		{
			privPixmap->bits_per_pixel = bitsPerPixel;
		}

		/* When this is called directly from X to create the front buffer, offset is zero as expected. When this
		 * function is called recursively to create the back buffer, offset is the offset within the fbdev to
		 * the second buffer */
		privPixmap->mem_info->offset = offset;

		/* Only wrap the other half if there is another half! */
		if (pPixData == fPtr->fbmem)
		{
			/* This is executed only when this function is called directly from X. We need to create the
			 * back buffer now because we can't "wrap" existing memory in a pixmap during DRI2CreateBuffer
			 * for the back buffer of the framebuffer. In DRI2CreateBuffer instead of allocating a new
			 * pixmap for the back buffer like we do for non-swappable windows, we'll just grab this pointer
			 * from the screen pixmap and return it. */

			PrivPixmap *other_privPixmap;

			offset = size;
			privPixmap->other_buffer = (*pScreen->CreatePixmap)(pScreen, width, height, depth, 0);

			/* Store a pointer to this pixmap in the one we just created. Both fbdev pixmaps are then
			 * accessible from the screen pixmap, whichever of the fbdev pixmaps happens to be the screen
			 * pixmap at the time */
			other_privPixmap = (PrivPixmap *)exaGetPixmapDriverPrivate(privPixmap->other_buffer);
			other_privPixmap->other_buffer = pPixmap;

			offset = 0;
		}

		INFO_MSG("Creating FRAMEBUFFER pixmap %p at offset %lu, privPixmap=%p\n", pPixmap, privPixmap->mem_info->offset, privPixmap);

		return TRUE;
	}

	if (pPixData)
	{
		/* When this happens we're being told to wrap existing pixmap data for which we don't know the UMP
		 * handle. We can and still need to wrap it but it won't be offscreen - we can't accelerate it in any
		 * way. */

		if (privPixmap->mem_info != NULL)
		{
			return TRUE;
		}

		return FALSE;
	}

	pPixmap->devKind = ((pPixmap->drawable.width * pPixmap->drawable.bitsPerPixel) + 7) / 8;
	pPixmap->devKind = MALI_ALIGN(pPixmap->devKind, 8);

	size = exaGetPixmapPitch(pPixmap) * pPixmap->drawable.height;

	/* allocate pixmap data */
	mem_info = privPixmap->mem_info;

	if (mem_info && mem_info->usize == size)
	{
		return TRUE;
	}

	if (mem_info && mem_info->usize != 0)
	{
		ump_reference_release(mem_info->handle);
		mem_info->handle = NULL;
		memset(privPixmap, 0, sizeof(*privPixmap));

		return TRUE;
	}

	if (!size)
	{
		return TRUE;
	}

	if (NULL == mem_info)
	{
		mem_info = calloc(1, sizeof(*mem_info));

		if (!mem_info)
		{
			ERROR_MSG("failed to allocate memory metadata");
			return FALSE;
		}
	}

	if (fPtr->use_cached_ump)
	{
		mem_info->handle = ump_ref_drv_allocate(size, UMP_REF_DRV_CONSTRAINT_PHYSICALLY_LINEAR | UMP_REF_DRV_CONSTRAINT_USE_CACHE);
	}
	else
	{
		mem_info->handle = ump_ref_drv_allocate(size, UMP_REF_DRV_CONSTRAINT_PHYSICALLY_LINEAR);
	}

	if (UMP_INVALID_MEMORY_HANDLE == mem_info->handle)
	{
		ERROR_MSG("failed to allocate UMP memory (%i bytes)", size);
		return FALSE;
	}

	mem_info->usize = size;
	privPixmap->mem_info = mem_info;
	privPixmap->mem_info->usize = size;
	privPixmap->bits_per_pixel = 16;

	return TRUE;
}