blob: d6663c57087e36f8f2eda961dd56ab63efdcd5c7 [file] [log] [blame]
/*
* Copyright © 2012 ARM Limited
*
* 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, sublicense,
* 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 NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS 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.
*
*/
#include <stdlib.h>
#include <sys/mman.h>
#include <assert.h>
#include <errno.h>
#include <xorg-server.h>
#include <xf86.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
#include "omap_dumb.h"
#include "omap_msg.h"
/* device related functions:
*/
struct omap_device *omap_device_new(int fd, ScrnInfoPtr pScrn)
{
struct omap_device *new_dev = calloc(1, sizeof *new_dev);
const struct bo_ops *bo_ops;
if (!new_dev)
return NULL;
new_dev->fd = fd;
new_dev->pScrn = pScrn;
if (!bo_device_init(new_dev))
goto err_free_dev;
bo_ops = new_dev->ops;
if (!(bo_ops->bo_create && bo_ops->bo_destroy
&& bo_ops->bo_get_name
&& bo_ops->bo_map
&& bo_ops->bo_cpu_prep
&& bo_ops->bo_cpu_fini)) {
ERROR_MSG("Omap Dev New Fail: bo_ops setting is Incomplete");
goto err_deinit_bodev;
}
return new_dev;
err_deinit_bodev:
bo_device_deinit(new_dev);
err_free_dev:
free(new_dev);
return NULL;
}
void omap_device_del(struct omap_device *dev)
{
bo_device_deinit(dev);
free(dev);
}
/* buffer-object related functions:
*/
static struct omap_bo *omap_bo_new(struct omap_device *dev, uint32_t width,
uint32_t height, uint8_t depth, uint8_t bpp,
uint32_t pixel_format)
{
ScrnInfoPtr pScrn = dev->pScrn;
const struct bo_ops *bo_ops = dev->ops;
struct omap_bo *new_buf;
uint32_t pitch;
size_t size;
const uint32_t flags = 0;
int ret;
new_buf = calloc(1, sizeof(*new_buf));
if (!new_buf)
return NULL;
/* align to 64 bytes since Mali requires it.
*/
pitch = ((((width * bpp + 7) / 8) + 63) / 64) * 64;
size = height * pitch;
new_buf->priv_bo = bo_ops->bo_create(dev, size, flags, &new_buf->handle);
if (!new_buf->priv_bo) {
ERROR_MSG("PLATFORM_BO_CREATE(size: %zu flags: 0x%x) failed: %s",
size, flags, strerror(errno));
goto free_buf;
}
if (depth) {
ret = drmModeAddFB(dev->fd, width, height, depth,
bpp, pitch, new_buf->handle,
&new_buf->fb_id);
if (ret < 0) {
ERROR_MSG("[BO:%u] add FB {%ux%u depth: %u bpp: %u pitch: %u} failed: %s",
new_buf->handle, width,
height, depth, bpp, pitch,
strerror(errno));
goto destroy_bo;
}
DEBUG_MSG("Created [FB:%u] {%ux%u depth: %u bpp: %u pitch: %u} using [BO:%u]",
new_buf->fb_id, width, height, depth, bpp,
pitch, new_buf->handle);
} else {
uint32_t handles[4] = { new_buf->handle };
uint32_t pitches[4] = { pitch };
uint32_t offsets[4] = { 0 };
ret = drmModeAddFB2(dev->fd, width, height,
pixel_format, handles, pitches, offsets,
&new_buf->fb_id, 0);
if (ret < 0) {
ERROR_MSG("[BO:%u] add FB {%ux%u format: %.4s pitch: %u} failed: %s",
new_buf->handle, width,
height, (char *)&pixel_format, pitch,
strerror(errno));
goto destroy_bo;
}
/* print pixel_format as a 'four-cc' ASCII code */
DEBUG_MSG("[BO:%u] [FB:%u] Added FB: {%ux%u format: %.4s pitch: %u}",
new_buf->handle, new_buf->fb_id,
width, height, (char *)&pixel_format, pitch);
}
new_buf->dev = dev;
new_buf->width = width;
new_buf->height = height;
new_buf->pitch = pitch;
new_buf->depth = depth;
new_buf->bpp = bpp;
new_buf->pixel_format = pixel_format;
new_buf->refcnt = 1;
new_buf->acquired_exclusive = 0;
new_buf->acquire_cnt = 0;
new_buf->dirty = TRUE;
return new_buf;
destroy_bo:
bo_ops->bo_destroy(new_buf);
free_buf:
free(new_buf);
return NULL;
}
struct omap_bo *omap_bo_new_with_depth(struct omap_device *dev, uint32_t width,
uint32_t height, uint8_t depth, uint8_t bpp)
{
return omap_bo_new(dev, width, height, depth, bpp, 0);
}
struct omap_bo *omap_bo_new_with_format(struct omap_device *dev, uint32_t width,
uint32_t height, uint32_t pixel_format, uint8_t bpp)
{
return omap_bo_new(dev, width, height, 0, bpp, pixel_format);
}
static void omap_bo_del(struct omap_bo *bo)
{
struct omap_device *dev = bo->dev;
ScrnInfoPtr pScrn = dev->pScrn;
int res;
res = drmModeRmFB(dev->fd, bo->fb_id);
if (res)
ERROR_MSG("[BO:%u] Remove [FB:%u] failed: %s",
bo->handle, bo->fb_id,
strerror(errno));
assert(res == 0);
dev->ops->bo_destroy(bo);
free(bo);
}
void omap_bo_unreference(struct omap_bo *bo)
{
if (!bo)
return;
assert(bo->refcnt > 0);
if (--bo->refcnt == 0)
omap_bo_del(bo);
}
void omap_bo_reference(struct omap_bo *bo)
{
assert(bo->refcnt > 0);
bo->refcnt++;
}
uint32_t omap_bo_get_name(struct omap_bo *bo)
{
struct omap_device *dev = bo->dev;
ScrnInfoPtr pScrn = dev->pScrn;
uint32_t name;
int ret;
ret = dev->ops->bo_get_name(bo, &name);
if (ret) {
ERROR_MSG("[BO:%u] BO_GET_NAME failed: %s",
bo->handle, strerror(errno));
return 0;
}
DEBUG_MSG("[BO:%u] [FB:%u] [FLINK:%u] ",
bo->handle, bo->fb_id, name);
return name;
}
uint32_t omap_bo_handle(struct omap_bo *bo)
{
return bo->handle;
}
uint32_t omap_bo_width(struct omap_bo *bo)
{
return bo->width;
}
uint32_t omap_bo_height(struct omap_bo *bo)
{
return bo->height;
}
uint32_t omap_bo_bpp(struct omap_bo *bo)
{
return bo->bpp;
}
/* Bytes per pixel */
uint32_t omap_bo_Bpp(struct omap_bo *bo)
{
return (bo->bpp + 7) / 8;
}
uint32_t omap_bo_pitch(struct omap_bo *bo)
{
return bo->pitch;
}
uint32_t omap_bo_depth(struct omap_bo *bo)
{
return bo->depth;
}
uint32_t omap_bo_fb(struct omap_bo *bo)
{
return bo->fb_id;
}
void *omap_bo_map(struct omap_bo *bo)
{
struct omap_device *dev = bo->dev;
ScrnInfoPtr pScrn = dev->pScrn;
void *map_addr;
map_addr = dev->ops->bo_map(bo);
if (!map_addr) {
ERROR_MSG("[BO:%u] bo_MAP failed: %s",
bo->handle, strerror(errno));
return NULL;
}
return map_addr;
}
int omap_bo_cpu_prep(struct omap_bo *bo, enum omap_gem_op op)
{
struct omap_device *dev = bo->dev;
ScrnInfoPtr pScrn = dev->pScrn;
int ret;
if (bo->acquire_cnt) {
if ((op & OMAP_GEM_WRITE) && !bo->acquired_exclusive) {
ERROR_MSG("attempting to acquire read locked surface for write");
return 1;
}
bo->acquire_cnt++;
return 0;
}
ret = dev->ops->bo_cpu_prep(bo, op);
if (!ret) {
bo->acquired_exclusive = op & OMAP_GEM_WRITE;
bo->acquire_cnt++;
if (bo->acquired_exclusive) {
bo->dirty = TRUE;
}
}
return ret;
}
int omap_bo_cpu_fini(struct omap_bo *bo, enum omap_gem_op op)
{
struct omap_device *dev = bo->dev;
assert(bo->acquire_cnt > 0);
if (--bo->acquire_cnt != 0) {
return 0;
}
return dev->ops->bo_cpu_fini(bo, op);
}
int omap_bo_get_dirty(struct omap_bo *bo)
{
return bo->dirty;
}
void omap_bo_clear_dirty(struct omap_bo *bo)
{
bo->dirty = FALSE;
}