Пример #1
0
static int
_cg_rect_slices_for_size(int size_to_fill,
                         int max_span_size,
                         int max_waste,
                         c_array_t *out_spans)
{
    int n_spans = 0;
    cg_span_t span;

    /* Init first slice span */
    span.start = 0;
    span.size = max_span_size;
    span.waste = 0;

    /* Repeat until whole area covered */
    while (size_to_fill >= span.size) {
        /* Add another slice span of same size */
        if (out_spans)
            c_array_append_val(out_spans, span);
        span.start += span.size;
        size_to_fill -= span.size;
        n_spans++;
    }

    /* Add one last smaller slice span */
    if (size_to_fill > 0) {
        span.size = size_to_fill;
        if (out_spans)
            c_array_append_val(out_spans, span);
        n_spans++;
    }

    return n_spans;
}
Пример #2
0
static int
_cg_pot_slices_for_size(int size_to_fill,
                        int max_span_size,
                        int max_waste,
                        c_array_t *out_spans)
{
    int n_spans = 0;
    cg_span_t span;

    /* Init first slice span */
    span.start = 0;
    span.size = max_span_size;
    span.waste = 0;

    /* Fix invalid max_waste */
    if (max_waste < 0)
        max_waste = 0;

    while (true) {
        /* Is the whole area covered? */
        if (size_to_fill > span.size) {
            /* Not yet - add a span of this size */
            if (out_spans)
                c_array_append_val(out_spans, span);

            span.start += span.size;
            size_to_fill -= span.size;
            n_spans++;
        } else if (span.size - size_to_fill <= max_waste) {
            /* Yes and waste is small enough */
            /* Pick the next power of two up from size_to_fill. This can
               sometimes be less than the span.size that would be chosen
               otherwise */
            span.size = _cg_util_next_p2(size_to_fill);
            span.waste = span.size - size_to_fill;
            if (out_spans)
                c_array_append_val(out_spans, span);

            return ++n_spans;
        } else {
            /* Yes but waste is too large */
            while (span.size - size_to_fill > max_waste) {
                span.size /= 2;
                c_assert(span.size > 0);
            }
        }
    }

    /* Can't get here */
    return 0;
}
Пример #3
0
static void
data_buffer_stream_read_idle(void *user_data)
{
    rig_pb_stream_t *stream = user_data;
    int i;

    rut_poll_shell_remove_idle_FIXME(stream->shell, stream->buffer.read_idle);
    stream->buffer.read_idle = NULL;

    c_return_if_fail(stream->type == STREAM_TYPE_BUFFER);
    c_return_if_fail(stream->buffer.other_end != NULL);
    c_return_if_fail(stream->buffer.other_end->type == STREAM_TYPE_BUFFER);
    c_return_if_fail(stream->read_callback != NULL);

    for (i = 0; i < stream->buffer.incoming_write_closures->len; i++) {
        rig_pb_stream_write_closure_t *closure =
            c_array_index(stream->buffer.incoming_write_closures, void *, i);

        stream->read_callback(stream,
                              (uint8_t *)closure->buf.base,
                              closure->buf.len,
                              stream->read_data);

        /* Give the closure back so it can be freed */
        c_array_append_val(stream->buffer.other_end->buffer.finished_write_closures,
                           closure);
    }
    c_array_set_size(stream->buffer.incoming_write_closures, 0);

    drain_finished_write_closures(stream);
}
Пример #4
0
void
rig_pb_stream_disconnect(rig_pb_stream_t *stream)
{
    switch (stream->type)
    {
#ifdef USE_UV
    case STREAM_TYPE_FD:
        uv_read_stop((uv_stream_t *)&stream->fd.uv_fd_pipe);
        uv_close((uv_handle_t *)&stream->fd.uv_fd_pipe,
                 NULL /* closed callback */);
        break;
    case STREAM_TYPE_TCP:
        uv_read_stop((uv_stream_t *)&stream->tcp.socket);
        uv_close((uv_handle_t *)&stream->tcp.socket,
                 NULL /* closed callback */);
        break;
#endif
    case STREAM_TYPE_BUFFER:
        {
            int i;

            /* Give all incoming write closures back to the other end
             * so they can be freed */
            for (i = 0; i < stream->buffer.incoming_write_closures->len; i++) {
                rig_pb_stream_write_closure_t *closure =
                    c_array_index(stream->buffer.incoming_write_closures, void *, i);

                c_array_append_val(stream->buffer.other_end->buffer.finished_write_closures,
                                   closure);
            }
            c_array_free(stream->buffer.incoming_write_closures,
                         true /* free storage */);
            stream->buffer.incoming_write_closures = NULL;

            drain_finished_write_closures(stream);

            c_array_free(stream->buffer.finished_write_closures,
                         true /* free storage */);
            stream->buffer.finished_write_closures = NULL;

            stream->buffer.other_end->buffer.other_end = NULL;
            stream->buffer.other_end = NULL;
        }

        if (stream->buffer.read_idle) {
            rut_poll_shell_remove_idle_FIXME(stream->shell, stream->buffer.read_idle);
            stream->buffer.read_idle = NULL;
        }
        break;

#ifdef __EMSCRIPTEN__
    case STREAM_TYPE_WORKER_IPC:
        stream->worker_ipc.worker = 0;
        break;

    case STREAM_TYPE_WEBSOCKET_CLIENT:
        if (stream->websocket_client.socket != -1) {
            close(stream->websocket_client.socket);
            stream->websocket_client.socket = -1;
        }
        break;
#endif

#ifdef USE_UV
    case STREAM_TYPE_WEBSOCKET_SERVER:
        stream->websocket_server.ctx = NULL;
        break;
#endif

    case STREAM_TYPE_DISCONNECTED:

#ifdef USE_UV
        if (stream->resolving)
            uv_cancel((uv_req_t *)&stream->resolver);
        if (stream->connecting)
            uv_cancel((uv_req_t *)&stream->connection_request);
#endif

        return;
    }

    stream->type = STREAM_TYPE_DISCONNECTED;

    rut_closure_list_invoke(&stream->on_error_closures,
                            rig_pb_stream_callback_t,
                            stream);
}
Пример #5
0
void
rig_pb_stream_write(rig_pb_stream_t *stream,
                    rig_pb_stream_write_closure_t *closure)
{
    c_return_if_fail(stream->type != STREAM_TYPE_DISCONNECTED);

    switch (stream->type) {
    case STREAM_TYPE_BUFFER: {
        c_return_if_fail(stream->buffer.other_end != NULL);
        c_return_if_fail(stream->buffer.other_end->type == STREAM_TYPE_BUFFER);

        c_array_append_val(stream->buffer.other_end->buffer.incoming_write_closures, closure);

        queue_data_buffer_stream_read(stream->buffer.other_end);

        break;
    }

#ifdef USE_UV
    case STREAM_TYPE_FD:
    case STREAM_TYPE_TCP: {
        closure->write_req.data = closure;

        uv_write(&closure->write_req,
                 (uv_stream_t *)&stream->fd.uv_fd_pipe,
                 &closure->buf,
                 1, /* n buffers */
                 uv_write_done_cb);
        break;
    }
    case STREAM_TYPE_WEBSOCKET_SERVER: {
        struct wslay_event_fragmented_msg arg;

        memset(&arg, 0, sizeof(arg));
        arg.opcode = WSLAY_BINARY_FRAME;
        arg.source.data = closure;
        arg.read_callback = fragmented_wslay_read_cb;

        closure->current_offset = 0;

        wslay_event_queue_fragmented_msg(stream->websocket_server.ctx, &arg);
        wslay_event_send(stream->websocket_server.ctx);
        break;
    }
#endif

#ifdef __EMSCRIPTEN__
    case STREAM_TYPE_WORKER_IPC:
        if (stream->worker_ipc.in_worker)
            rig_emscripten_worker_post_to_main(closure->buf.base,
                                               closure->buf.len);
        else
            rig_emscripten_worker_post(stream->worker_ipc.worker,
                                       "rig_pb_stream_worker_onmessage",
                                       closure->buf.base,
                                       closure->buf.len);

        closure->done_callback(closure);
        break;

    case STREAM_TYPE_WEBSOCKET_CLIENT:
        c_debug("stream: websocket send() %d bytes", closure->buf.len);
        send(stream->websocket_client.socket,
             closure->buf.base,
             closure->buf.len,
             0 /* flags */);

        closure->done_callback(closure);
        break;
#endif

    case STREAM_TYPE_DISCONNECTED:
        c_warn_if_reached();
        break;
    }
}
Пример #6
0
static bool
setup_spans(cg_device_t *dev,
            cg_texture_2d_sliced_t *tex_2ds,
            int width,
            int height,
            int max_waste,
            cg_pixel_format_t internal_format,
            cg_error_t **error)
{
    int max_width;
    int max_height;
    int n_x_slices;
    int n_y_slices;

    int (*slices_for_size)(int, int, int, c_array_t *);

    /* Initialize size of largest slice according to supported features */
    if (cg_has_feature(dev, CG_FEATURE_ID_TEXTURE_NPOT)) {
        max_width = width;
        max_height = height;
        slices_for_size = _cg_rect_slices_for_size;
    } else {
        max_width = _cg_util_next_p2(width);
        max_height = _cg_util_next_p2(height);
        slices_for_size = _cg_pot_slices_for_size;
    }

    /* Negative number means no slicing forced by the user */
    if (max_waste <= -1) {
        cg_span_t span;

        /* Check if size supported else bail out */
        if (!dev->driver_vtable->texture_2d_can_create(dev, max_width, max_height, internal_format)) {
            _cg_set_error(error,
                          CG_TEXTURE_ERROR,
                          CG_TEXTURE_ERROR_SIZE,
                          "Sliced texture size of %d x %d not possible "
                          "with max waste set to -1",
                          width,
                          height);
            return false;
        }

        n_x_slices = 1;
        n_y_slices = 1;

        /* Init span arrays */
        tex_2ds->slice_x_spans =
            c_array_sized_new(false, false, sizeof(cg_span_t), 1);

        tex_2ds->slice_y_spans =
            c_array_sized_new(false, false, sizeof(cg_span_t), 1);

        /* Add a single span for width and height */
        span.start = 0;
        span.size = max_width;
        span.waste = max_width - width;
        c_array_append_val(tex_2ds->slice_x_spans, span);

        span.size = max_height;
        span.waste = max_height - height;
        c_array_append_val(tex_2ds->slice_y_spans, span);
    } else {
        /* Decrease the size of largest slice until supported by GL */
        while (!dev->driver_vtable->texture_2d_can_create(dev, max_width, max_height, internal_format)) {
            /* Alternate between width and height */
            if (max_width > max_height)
                max_width /= 2;
            else
                max_height /= 2;

            if (max_width == 0 || max_height == 0) {
                /* Maybe it would be ok to just c_warn_if_reached() for this
                 * codepath */
                _cg_set_error(error,
                              CG_TEXTURE_ERROR,
                              CG_TEXTURE_ERROR_SIZE,
                              "No suitable slice geometry found");
                free_spans(tex_2ds);
                return false;
            }
        }

        /* Determine the slices required to cover the bitmap area */
        n_x_slices = slices_for_size(width, max_width, max_waste, NULL);

        n_y_slices = slices_for_size(height, max_height, max_waste, NULL);

        /* Init span arrays with reserved size */
        tex_2ds->slice_x_spans =
            c_array_sized_new(false, false, sizeof(cg_span_t), n_x_slices);

        tex_2ds->slice_y_spans =
            c_array_sized_new(false, false, sizeof(cg_span_t), n_y_slices);

        /* Fill span arrays with info */
        slices_for_size(width, max_width, max_waste, tex_2ds->slice_x_spans);

        slices_for_size(height, max_height, max_waste, tex_2ds->slice_y_spans);
    }

    return true;
}