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; }