Skip to content
This repository has been archived by the owner on Sep 21, 2021. It is now read-only.

Commit

Permalink
Merge pull request #152 from misson20000/fix-tearing
Browse files Browse the repository at this point in the history
fix tearing
  • Loading branch information
misson20000 authored May 31, 2018
2 parents 4548ae6 + cacc802 commit 207deca
Show file tree
Hide file tree
Showing 10 changed files with 160 additions and 54 deletions.
9 changes: 5 additions & 4 deletions include/libtransistor/display/fence.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ extern "C" {
#include<libtransistor/types.h>

/**
* @struct fence_t
* @brief Description here...
*/
* @struct fence_t
* @brief Represents conditions for the completion of an asynchronous graphics operation
*/
typedef struct {
uint32_t unknown[11];
uint32_t is_valid;
gpu_fence_t sync[4];
} fence_t;

#ifdef __cplusplus
Expand Down
9 changes: 6 additions & 3 deletions include/libtransistor/display/graphic_buffer_queue.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,14 +81,17 @@ typedef enum {
* https://source.android.com/reference/hidl/android/hardware/graphics/bufferqueue/1.0/IGraphicBufferProducer#queuebufferinput
*/
typedef struct {
uint32_t size;
uint32_t num_fds;
int64_t timestamp;
bool is_auto_timestamp;
int32_t is_auto_timestamp;
rect_t crop;
int32_t scaling_mode;
uint32_t transform;
uint32_t sticky_transform;
uint32_t unknown[2];
fence_t fence;
// and a few more unknown fields
} queue_buffer_input_t;
} __attribute__((packed)) queue_buffer_input_t;

/**
* @struct queue_buffer_output_t
Expand Down
12 changes: 10 additions & 2 deletions include/libtransistor/display/surface.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,14 @@ typedef struct {
surface_state_t state;
bool has_requested[2];
uint32_t current_slot;

gpu_buffer_t gpu_buffer;
uint32_t *gpu_buffer_memory;
uint32_t *gpu_buffer_memory_alloc;

graphic_buffer_t graphic_buffers[3];

fence_t current_fence;
} surface_t;

/**
Expand All @@ -59,9 +61,15 @@ result_t surface_create(surface_t *surface, uint64_t layer_id, igbp_t igbp);
* Using \ref gfx_slow_swizzling_blit is recommended. Call \ref surface_queue_buffer
* when you're done rendering to submit it to be displayed.
*/
// for now, we ignore fences
result_t surface_dequeue_buffer(surface_t *surface, uint32_t **image);

/**
* @brief Wait for any asynchronous operations on the current buffer to complete
*
* @param surface Surface
*/
result_t surface_wait_buffer(surface_t *surface);

/**
* @brief Submit the current buffer to be displayed
*
Expand Down
3 changes: 2 additions & 1 deletion include/libtransistor/err.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ extern "C" {
#define LIBTRANSISTOR_ERR_SURFACE_DEQUEUE_BUFFER_FAILED LIBTRANSISTOR_RESULT(5007)
#define LIBTRANSISTOR_ERR_SURFACE_QUEUE_BUFFER_FAILED LIBTRANSISTOR_RESULT(5008)
#define LIBTRANSISTOR_ERR_SURFACE_INVALID_STATE LIBTRANSISTOR_RESULT(5009)

#define LIBTRANSISTOR_ERR_DISPLAY_INVALID_FENCE LIBTRANSISTOR_RESULT(5010)

// GPU
#define LIBTRANSISTOR_ERR_GPU_BUFFER_UNALIGNED LIBTRANSISTOR_RESULT(6001)

Expand Down
13 changes: 13 additions & 0 deletions include/libtransistor/gpu/gpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ typedef struct {
uint8_t kind;
} gpu_buffer_t;

typedef struct {
uint32_t syncpt_id;
uint32_t syncpt_value;
} gpu_fence_t;

/**
* @brief Initialize GPU
*/
Expand Down Expand Up @@ -63,6 +68,14 @@ result_t gpu_buffer_get_id(gpu_buffer_t *gpu_b, uint32_t *id);
*/
result_t gpu_buffer_initialize_from_id(gpu_buffer_t *gpu_b, uint32_t id);


/**
* @brief Waits on a fence to complete
*
* @param fence Fence to wait for completion on
*/
result_t gpu_wait_fence(gpu_fence_t *fence, uint32_t timeout);

/**
* @brief Finalize GPU
*/
Expand Down
42 changes: 26 additions & 16 deletions include/libtransistor/gpu/nv_ioc.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,20 @@
extern "C" {
#endif

#define NVHOST_IOCTL_CTRL_SYNCPT_READ 0xC0080014
#define NVHOST_IOCTL_CTRL_SYNCPT_INCR 0x40040015
#define NVHOST_IOCTL_CTRL_SYNCPT_WAIT 0xC00C0016
#define NVHOST_IOCTL_CTRL_MODULE_MUTEX 0x40080017
#define NVHOST_IOCTL_CTRL_MODULE_REGRDWR 0xC0180018
#define NVHOST_IOCTL_CTRL_SYNCPT_WAITEX 0xC0100019
#define NVHOST_IOCTL_CTRL_SYNCPT_READ_MAX 0xC008001A
#define NVHOST_IOCTL_CTRL_GET_CONFIG 0xC183001B
#define NVHOST_IOCTL_CTRL_EVENT_SIGNAL 0xC004001C
#define NVHOST_IOCTL_CTRL_EVENT_WAIT 0xC010001D
#define NVHOST_IOCTL_CTRL_EVENT_WAIT_ASYNC 0xC010001E
#define NVHOST_IOCTL_CTRL_EVENT_REGISTER 0xC004001F
#define NVHOST_IOCTL_CTRL_EVENT_UNREGISTER 0xC0040020
#define NVHOST_IOCTL_CTRL_EVENT_KILL 0x40080021
#define NVHOST_IOC_CTRL_SYNCPT_READ 0xC0080014
#define NVHOST_IOC_CTRL_SYNCPT_INCR 0x40040015
#define NVHOST_IOC_CTRL_SYNCPT_WAIT 0xC00C0016
#define NVHOST_IOC_CTRL_MODULE_MUTEX 0x40080017
#define NVHOST_IOC_CTRL_MODULE_REGRDWR 0xC0180018
#define NVHOST_IOC_CTRL_SYNCPT_WAITEX 0xC0100019
#define NVHOST_IOC_CTRL_SYNCPT_READ_MAX 0xC008001A
#define NVHOST_IOC_CTRL_GET_CONFIG 0xC183001B
#define NVHOST_IOC_CTRL_EVENT_SIGNAL 0xC004001C
#define NVHOST_IOC_CTRL_EVENT_WAIT 0xC010001D
#define NVHOST_IOC_CTRL_EVENT_WAIT_ASYNC 0xC010001E
#define NVHOST_IOC_CTRL_EVENT_REGISTER 0xC004001F
#define NVHOST_IOC_CTRL_EVENT_UNREGISTER 0xC0040020
#define NVHOST_IOC_CTRL_EVENT_KILL 0x40080021

#define NVMAP_IOC_CREATE 0xC0080101
#define NVMAP_IOC_FROM_ID 0xC0080103
Expand All @@ -32,15 +32,25 @@ extern "C" {
#define NVMAP_IOC_GET_ID 0xC008010E

/**
* @struct nvhost_ioctl_ctrl_event_wait_args
* @struct nvhost_ioctl_ctrl_syncpt_wait_args
* @brief Arguments to wait on a syncpt
*/
typedef struct {
uint32_t syncpt_id; ///< In
uint32_t threshold; ///< In
int32_t timeout; ///< In
} nvhost_ioc_ctrl_syncpt_wait_args;

/**
* @struct nvhost_ioctl_ctrl_event_wait_args
* @brief Arguments to wait on a syncpt event
*/
typedef struct {
uint32_t syncpt_id; ///< In
uint32_t threshold; ///< In
int32_t timeout; ///< In
uint32_t value; ///< Inout
} nvhost_ioctl_ctrl_event_wait_args;
} nvhost_ioc_ctrl_event_wait_args;

/**
* @struct nvmap_ioc_create_args
Expand Down
47 changes: 24 additions & 23 deletions lib/display/graphic_buffer_queue.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,26 +41,7 @@ static result_t queue_buffer_output_unflatten(parcel_t *parcel, queue_buffer_out
}

static result_t queue_buffer_input_flatten(parcel_t *parcel, queue_buffer_input_t *qbi) {
static uint32_t ts32 = 0x588bbba9;
uint32_t template[] = {
0x54, 0, // unknown, but always these values
ts32, 0x0, //u64 timestamp
1, 0, 0, // unknown, but always these values
0, 0, // sometimes zero
0,
0, // also seen 2

0, 0,

// fence?
1, 1, 0xa3, 0x0,
-1, 0, -1, 0, -1, 0
};

ts32++;
//ts32+= 0x2e45f00;

memcpy(parcel_write_inplace(parcel, sizeof(template)), &template, sizeof(template));
memcpy(parcel_write_inplace(parcel, sizeof(*qbi)), qbi, sizeof(*qbi));

return RESULT_OK;
}
Expand Down Expand Up @@ -127,6 +108,20 @@ static result_t graphic_buffer_flatten(parcel_t *parcel, graphic_buffer_t *gb) {
}

static result_t fence_unflatten(parcel_t *parcel, fence_t *fence) {
struct {
uint32_t size;
uint32_t num_fds;
} *header;
header = parcel_read_inplace(parcel, sizeof(*header));
if(header->size != sizeof(fence_t)) {
return LIBTRANSISTOR_ERR_DISPLAY_INVALID_FENCE;
}
if(header->num_fds != 0) {
return LIBTRANSISTOR_ERR_DISPLAY_FENCE_TOO_MANY_FDS;
}
for(size_t i = 0; i < ARRAY_LENGTH(fence->sync); i++) {
fence->sync[i].syncpt_id = 0xffffffff;
}
memcpy(fence, parcel_read_inplace(parcel, sizeof(*fence)), sizeof(*fence));
return RESULT_OK;
}
Expand Down Expand Up @@ -182,11 +177,17 @@ result_t igbp_dequeue_buffer(igbp_t *igbp, uint32_t width, uint32_t height, pixe
}

*slot = parcel_read_u32(&response);
if((r = fence_unflatten(&response, fence)) != RESULT_OK) {
return r;

int32_t has_fence = parcel_read_u32(&response);
if(has_fence) {
if((r = fence_unflatten(&response, fence)) != RESULT_OK) {
return r;
}
} else {
fence->is_valid = false;
}
*status = parcel_read_u32(&response);

return RESULT_OK;
}

Expand Down
48 changes: 45 additions & 3 deletions lib/display/surface.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,11 @@ result_t surface_dequeue_buffer(surface_t *surface, uint32_t **image) {
}

int status;
fence_t fence;
if((r = igbp_dequeue_buffer(
&surface->igbp,
1280, 720, 1, 0xb00,
false, &status, &surface->current_slot,
&fence, NULL)) != RESULT_OK) {
&surface->current_fence, NULL)) != RESULT_OK) {
return r;
}

Expand Down Expand Up @@ -144,11 +143,31 @@ result_t surface_queue_buffer(surface_t *surface) {
if(surface->state != SURFACE_STATE_DEQUEUED) {
return LIBTRANSISTOR_ERR_SURFACE_INVALID_STATE;
}

queue_buffer_input_t qbi;
qbi.size = sizeof(qbi) - 0x8;
qbi.num_fds = 0;
qbi.timestamp = 0;
qbi.is_auto_timestamp = 0;
qbi.crop.left = 0;
qbi.crop.top = 0;
qbi.crop.right = 0;
qbi.crop.bottom = 0;
qbi.scaling_mode = 0;
qbi.transform = 0;
qbi.sticky_transform = 0;
qbi.unknown[0] = 0;
qbi.unknown[1] = 1;
qbi.fence.is_valid = 1;
for(size_t i = 0; i < ARRAY_LENGTH(qbi.fence.sync); i++) {
qbi.fence.sync[i].syncpt_id = 0xffffffff;
qbi.fence.sync[i].syncpt_value = 0;
}

queue_buffer_output_t qbo;
int status;
if((r = igbp_queue_buffer(&surface->igbp, surface->current_slot,
NULL, &qbo, &status)) != RESULT_OK) {
&qbi, &qbo, &status)) != RESULT_OK) {
return r;
}

Expand All @@ -160,3 +179,26 @@ result_t surface_queue_buffer(surface_t *surface) {

return RESULT_OK;
}

result_t surface_wait_buffer(surface_t *surface) {
if(surface->state != SURFACE_STATE_DEQUEUED) {
return LIBTRANSISTOR_ERR_SURFACE_INVALID_STATE;
}

if(!surface->current_fence.is_valid) {
return RESULT_OK;
}

for(size_t i = 0; i < ARRAY_LENGTH(surface->current_fence.sync); i++) {
result_t r;
gpu_fence_t *f = &surface->current_fence.sync[i];
if(f->syncpt_id == 0xffffffff) {
continue;
}
if((r = gpu_wait_fence(f, -1)) != RESULT_OK) {
return r;
}
}

return RESULT_OK;
}
24 changes: 24 additions & 0 deletions lib/gpu/gpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

static int nvas_fd;
static int nvmap_fd;
static int nvhost_ctrl_fd;
static int gpu_initializations = 0;

result_t gpu_initialize() {
Expand All @@ -29,8 +30,15 @@ result_t gpu_initialize() {
goto fail_nvas;
}

if((nvhost_ctrl_fd = nv_open("/dev/nvhost-ctrl")) < 0) {
r = nv_result;
goto fail_nvmap;
}

return RESULT_OK;

fail_nvhost_ctrl:
nv_close(nvhost_ctrl_fd);
fail_nvmap:
nv_close(nvmap_fd);
fail_nvas:
Expand Down Expand Up @@ -140,7 +148,23 @@ result_t gpu_buffer_initialize_from_id(gpu_buffer_t *gpu_b, uint32_t id) {
return RESULT_OK;
}

result_t gpu_wait_fence(gpu_fence_t *fence, uint32_t timeout) {
INITIALIZATION_GUARD(gpu);

nvhost_ioc_ctrl_syncpt_wait_args nvh_wait;
nvh_wait.syncpt_id = fence->syncpt_id;
nvh_wait.threshold = fence->syncpt_value;
nvh_wait.timeout = timeout;

if(nv_ioctl(nvhost_ctrl_fd, NVHOST_IOC_CTRL_SYNCPT_WAIT, &nvh_wait, sizeof(nvh_wait)) != 0) {
return nv_result;
}

return RESULT_OK;
}

static void gpu_force_finalize() {
nv_close(nvhost_ctrl_fd);
nv_close(nvmap_fd);
nv_close(nvas_fd);
nv_finalize();
Expand Down
7 changes: 5 additions & 2 deletions test/test_display.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,12 @@ int main() {
printf("begin frame %d\n", i);
uint32_t *out_buffer;
ASSERT_OK(fail_display_event, surface_dequeue_buffer(&surf, &out_buffer));

if(i < 300) {
ASSERT_OK(fail_display_event, surface_wait_buffer(&surf));
}

for(size_t p = 0; p < (0x3c0000/sizeof(uint32_t)); p++) {
out_buffer[p] = 0xFF0000FF;
out_buffer[p] = (i < 300) ? 0xFFFF0000 : 0xFF0000FF;
}
int x = (cos((double) i * 6.28 / 60.0) * 300.0 + 350.0);
int y = (sin((double) i * 6.28 / 60.0) * 300.0 + 350.0);
Expand Down

0 comments on commit 207deca

Please sign in to comment.