mirror of
https://github.com/Yours3lf/rpi-vk-driver.git
synced 2024-11-29 11:24:14 +01:00
a071ec3d77
the validation layer doesn't like my direct to display implementation, but it might be buggy
375 lines
10 KiB
C
375 lines
10 KiB
C
#include "modeset.h"
|
|
|
|
#include <stdatomic.h>
|
|
atomic_int saved_state_guard = 0;
|
|
|
|
void modeset_enum_planes(int fd, uint32_t* numPlanes, modeset_plane* planes)
|
|
{
|
|
drmModePlaneResPtr planesPtr = drmModeGetPlaneResources(fd);
|
|
|
|
uint32_t numDisplays;
|
|
modeset_display displays[16];
|
|
modeset_enum_displays(controlFd, &numDisplays, displays);
|
|
|
|
uint32_t tmpNumPlanes = 0;
|
|
modeset_plane tmpPlanes[32];
|
|
|
|
for(uint32_t c = 0; c < planesPtr->count_planes; ++c)
|
|
{
|
|
tmpPlanes[tmpNumPlanes].plane = drmModeGetPlane(fd, planesPtr->planes[c]);
|
|
tmpPlanes[tmpNumPlanes].currentConnectorID = 0;
|
|
|
|
if(tmpPlanes[tmpNumPlanes].plane->crtc_id)
|
|
{
|
|
for(uint32_t d = 0; d < numDisplays; ++d)
|
|
{
|
|
drmModeConnectorPtr connPtr = drmModeGetConnector(fd, displays[d].connectorID);
|
|
|
|
drmModeEncoderPtr encPtr = drmModeGetEncoder(fd, connPtr->encoder_id);
|
|
|
|
uint32_t connID = connPtr->connector_id;
|
|
uint32_t crtcID = encPtr->crtc_id;
|
|
|
|
drmModeFreeConnector(connPtr);
|
|
drmModeFreeEncoder(encPtr);
|
|
|
|
if(crtcID == tmpPlanes[tmpNumPlanes].plane->crtc_id)
|
|
{
|
|
tmpPlanes[tmpNumPlanes].currentConnectorID = connID;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
tmpPlanes[tmpNumPlanes].numPossibleConnectors = 0;
|
|
|
|
for(uint32_t d = 0; d < numDisplays; ++d)
|
|
{
|
|
drmModeConnectorPtr connPtr = drmModeGetConnector(fd, displays[d].connectorID);
|
|
|
|
for(uint32_t e = 0; e < connPtr->count_encoders; ++e)
|
|
{
|
|
drmModeEncoderPtr encPtr = drmModeGetEncoder(fd, connPtr->encoders[e]);
|
|
|
|
uint32_t possibleCrtcs = encPtr->possible_crtcs;
|
|
|
|
drmModeFreeEncoder(encPtr);
|
|
|
|
if(possibleCrtcs & tmpPlanes[tmpNumPlanes].plane->possible_crtcs)
|
|
{
|
|
tmpPlanes[tmpNumPlanes].possibleConnectors[tmpPlanes[tmpNumPlanes].numPossibleConnectors] = connPtr->connector_id;
|
|
tmpPlanes[tmpNumPlanes].numPossibleConnectors++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
drmModeFreeConnector(connPtr);
|
|
}
|
|
|
|
tmpNumPlanes++;
|
|
|
|
assert(tmpNumPlanes < 32);
|
|
}
|
|
|
|
drmModeFreePlaneResources(planesPtr);
|
|
|
|
*numPlanes = tmpNumPlanes;
|
|
|
|
memcpy(planes, tmpPlanes, tmpNumPlanes * sizeof(modeset_plane));
|
|
|
|
for(uint32_t c = 0; c < tmpNumPlanes; ++c)
|
|
{
|
|
memcpy(planes[c].possibleConnectors, tmpPlanes[c].possibleConnectors, tmpPlanes[c].numPossibleConnectors * sizeof(uint32_t));
|
|
}
|
|
}
|
|
|
|
void modeset_enum_displays(int fd, uint32_t* numDisplays, modeset_display* displays)
|
|
{
|
|
drmModeResPtr resPtr = drmModeGetResources(fd);
|
|
|
|
uint32_t tmpNumDisplays = 0;
|
|
modeset_display tmpDisplays[16];
|
|
|
|
for(uint32_t c = 0; c < resPtr->count_connectors; ++c)
|
|
{
|
|
drmModeConnectorPtr connPtr = drmModeGetConnector(fd, resPtr->connectors[c]);
|
|
|
|
if(connPtr->connection != DRM_MODE_CONNECTED)
|
|
{
|
|
continue; //skip unused connector
|
|
}
|
|
|
|
if(!connPtr->count_modes)
|
|
{
|
|
continue; //skip connectors with no valid modes
|
|
}
|
|
|
|
memcpy(tmpDisplays[tmpNumDisplays].name, connPtr->modes[0].name, 32);
|
|
|
|
tmpDisplays[tmpNumDisplays].mmWidth = connPtr->mmWidth;
|
|
tmpDisplays[tmpNumDisplays].mmHeight = connPtr->mmHeight;
|
|
tmpDisplays[tmpNumDisplays].resWidth = connPtr->modes[0].hdisplay;
|
|
tmpDisplays[tmpNumDisplays].resHeight = connPtr->modes[0].vdisplay;
|
|
tmpDisplays[tmpNumDisplays].connectorID = connPtr->connector_id;
|
|
|
|
tmpNumDisplays++;
|
|
|
|
assert(tmpNumDisplays < 16);
|
|
|
|
drmModeFreeConnector(connPtr);
|
|
}
|
|
|
|
drmModeFreeResources(resPtr);
|
|
|
|
*numDisplays = tmpNumDisplays;
|
|
|
|
memcpy(displays, tmpDisplays, tmpNumDisplays * sizeof(modeset_display));
|
|
}
|
|
|
|
void modeset_enum_modes_for_display(int fd, uint32_t display, uint32_t* numModes, modeset_display_mode* modes)
|
|
{
|
|
drmModeResPtr resPtr = drmModeGetResources(fd);
|
|
|
|
drmModeConnectorPtr connPtr = drmModeGetConnector(fd, display);
|
|
|
|
if(!connPtr)
|
|
{
|
|
*numModes = 0;
|
|
return;
|
|
}
|
|
|
|
uint32_t tmpNumModes = 0;
|
|
modeset_display_mode tmpModes[1024];
|
|
|
|
for(uint32_t c = 0; c < connPtr->count_modes; ++c)
|
|
{
|
|
tmpModes[tmpNumModes].connectorID = display;
|
|
tmpModes[tmpNumModes].modeID = c;
|
|
tmpModes[tmpNumModes].refreshRate = connPtr->modes[c].vrefresh;
|
|
tmpModes[tmpNumModes].resWidth = connPtr->modes[c].hdisplay;
|
|
tmpModes[tmpNumModes].resHeight = connPtr->modes[c].vdisplay;
|
|
|
|
tmpNumModes++;
|
|
|
|
assert(tmpNumModes < 1024);
|
|
}
|
|
|
|
drmModeFreeConnector(connPtr);
|
|
drmModeFreeResources(resPtr);
|
|
|
|
*numModes = tmpNumModes;
|
|
memcpy(modes, tmpModes, tmpNumModes * sizeof(modeset_display_mode));
|
|
}
|
|
|
|
void modeset_create_surface_for_mode(int fd, uint32_t display, uint32_t mode, modeset_display_surface* surface)
|
|
{
|
|
// modeset_debug_print(fd);
|
|
|
|
surface->savedState = 0;
|
|
|
|
drmModeResPtr resPtr = drmModeGetResources(fd);
|
|
|
|
drmModeConnectorPtr connPtr = drmModeGetConnector(fd, display);
|
|
|
|
if(!connPtr)
|
|
{
|
|
return;
|
|
}
|
|
|
|
uint32_t found = 0;
|
|
|
|
//if current encoder is valid, try to use that
|
|
if(connPtr->encoder_id)
|
|
{
|
|
drmModeEncoderPtr encPtr = drmModeGetEncoder(fd, connPtr->encoder_id);
|
|
|
|
if(encPtr && encPtr->crtc_id)
|
|
{
|
|
surface->connector = connPtr;
|
|
surface->modeID = mode;
|
|
surface->crtc = drmModeGetCrtc(fd, encPtr->crtc_id);
|
|
|
|
found = 1;
|
|
}
|
|
|
|
drmModeFreeEncoder(encPtr);
|
|
}
|
|
|
|
if(!found)
|
|
{
|
|
// To find a suitable CRTC, you need to iterate over the list of encoders that are available
|
|
// for each connector. Each encoder contains a list of CRTCs that it can work with and you
|
|
// simply select one of these CRTCs. If you later program the CRTC to control a connector,
|
|
// it automatically selects the best encoder
|
|
|
|
// TODO if we were to output to multiple displays, we'd need to make sure we don't use a CRTC
|
|
// that we'd be using to drive the other screen
|
|
|
|
for(uint32_t c = 0; c < connPtr->count_encoders; ++c)
|
|
{
|
|
drmModeEncoderPtr encPtr = drmModeGetEncoder(fd, connPtr->encoders[c]);
|
|
|
|
for(uint32_t d = 0; d < 32; ++d)
|
|
{
|
|
if(encPtr->possible_crtcs & (1 << d))
|
|
{
|
|
surface->connector = connPtr;
|
|
surface->modeID = mode;
|
|
surface->crtc = drmModeGetCrtc(fd, resPtr->crtcs[d]);
|
|
|
|
found = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(found)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
drmModeFreeResources(resPtr);
|
|
|
|
//fprintf(stderr, "connector id %i, crtc id %i\n", connPtr->connector_id, encPtr->crtc_id);
|
|
}
|
|
|
|
void modeset_create_fb_for_surface(int fd, _image* buf, modeset_display_surface* surface)
|
|
{
|
|
int ret = drmModeAddFB(fd, buf->width, buf->height, 24, 32, buf->stride, buf->boundMem->bo, &buf->fb);
|
|
|
|
if(ret)
|
|
{
|
|
buf->fb = 0;
|
|
fprintf(stderr, "cannot create framebuffer (%d): %m\n", errno);
|
|
}
|
|
}
|
|
|
|
void modeset_destroy_fb(int fd, _image* buf)
|
|
{
|
|
// delete framebuffer
|
|
drmModeRmFB(fd, buf->fb);
|
|
}
|
|
|
|
void modeset_present(int fd, _image *buf, modeset_display_surface* surface)
|
|
{
|
|
if(!surface->savedState)
|
|
{
|
|
while(saved_state_guard);
|
|
saved_state_guard = 1;
|
|
|
|
for(uint32_t c = 0; c < 32; ++c)
|
|
{
|
|
if(!modeset_saved_states[c].used)
|
|
{
|
|
drmModeConnectorPtr tmpConnPtr = drmModeGetConnector(fd, surface->connector->connector_id);
|
|
drmModeCrtcPtr tmpCrtcPtr = drmModeGetCrtc(fd, surface->crtc->crtc_id);
|
|
modeset_saved_states[c].used = 1;
|
|
modeset_saved_states[c].conn = tmpConnPtr;
|
|
modeset_saved_states[c].crtc = tmpCrtcPtr;
|
|
surface->savedState = c;
|
|
break;
|
|
}
|
|
}
|
|
|
|
saved_state_guard = 0;
|
|
}
|
|
|
|
//fprintf(stderr, "present connector id %i, crtc id %i, fb %i\n", surface->connector->connector_id, surface->crtc->crtc_id, buf->fb);
|
|
int ret = drmModeSetCrtc(fd, surface->crtc->crtc_id, buf->fb, 0, 0, &surface->connector->connector_id, 1, &surface->connector->modes[surface->modeID]);
|
|
if(ret)
|
|
{
|
|
fprintf(stderr, "cannot flip CRTC for connector %u (%d): %m\n",
|
|
surface->connector->connector_id, errno);
|
|
}
|
|
|
|
//modeset_debug_print(fd);
|
|
}
|
|
|
|
void modeset_destroy_surface(int fd, modeset_display_surface *surface)
|
|
{
|
|
//restore old state
|
|
drmModeSetCrtc(fd, modeset_saved_states[surface->savedState].crtc->crtc_id,
|
|
modeset_saved_states[surface->savedState].crtc->buffer_id,
|
|
modeset_saved_states[surface->savedState].crtc->x,
|
|
modeset_saved_states[surface->savedState].crtc->y,
|
|
&modeset_saved_states[surface->savedState].conn->connector_id,
|
|
1,
|
|
&modeset_saved_states[surface->savedState].crtc->mode);
|
|
|
|
{
|
|
while(saved_state_guard);
|
|
saved_state_guard = 1;
|
|
|
|
drmModeFreeConnector(modeset_saved_states[surface->savedState].conn);
|
|
drmModeFreeCrtc(modeset_saved_states[surface->savedState].crtc);
|
|
modeset_saved_states[surface->savedState].used = 0;
|
|
|
|
saved_state_guard = 0;
|
|
}
|
|
|
|
drmModeFreeConnector(surface->connector);
|
|
drmModeFreeCrtc(surface->crtc);
|
|
}
|
|
|
|
void modeset_debug_print(int fd)
|
|
{
|
|
drmModeResPtr resPtr = drmModeGetResources(fd);
|
|
printf("res min width %i height %i\n", resPtr->min_width, resPtr->min_height);
|
|
printf("res max width %i height %i\n", resPtr->max_width, resPtr->max_height);
|
|
|
|
printf("\ncrtc count %i\n", resPtr->count_crtcs);
|
|
for(uint32_t c = 0; c < resPtr->count_crtcs; ++c)
|
|
{
|
|
drmModeCrtcPtr tmpCrtcPtr = drmModeGetCrtc(fd, resPtr->crtcs[c]);
|
|
printf("crtc id %i, buffer id %i\n", tmpCrtcPtr->crtc_id, tmpCrtcPtr->buffer_id);
|
|
drmModeFreeCrtc(tmpCrtcPtr);
|
|
}
|
|
|
|
printf("\nfb count %i\n", resPtr->count_fbs);
|
|
for(uint32_t c = 0; c < resPtr->count_fbs; ++c)
|
|
{
|
|
drmModeFBPtr tmpFBptr = drmModeGetFB(fd, resPtr->fbs[c]);
|
|
printf("fb id %i, handle %i\n", tmpFBptr->fb_id, tmpFBptr->handle);
|
|
drmModeFreeFB(tmpFBptr);
|
|
}
|
|
|
|
printf("\nencoder count %i\n", resPtr->count_encoders);
|
|
for(uint32_t c = 0; c < resPtr->count_encoders; ++c)
|
|
{
|
|
drmModeEncoderPtr tmpEncoderPtr = drmModeGetEncoder(fd, resPtr->encoders[c]);
|
|
printf("encoder id %i, crtc id %i\n", tmpEncoderPtr->encoder_id, tmpEncoderPtr->crtc_id);
|
|
printf("possible crtcs: ");
|
|
for(uint32_t c = 0; c < 32; ++c)
|
|
{
|
|
if(tmpEncoderPtr->possible_crtcs & (1 << c))
|
|
{
|
|
printf("%i, ", c);
|
|
}
|
|
}
|
|
printf("\n");
|
|
|
|
printf("possible clones: ");
|
|
for(uint32_t c = 0; c < 32; ++c)
|
|
{
|
|
if(tmpEncoderPtr->possible_clones & (1 << c))
|
|
{
|
|
printf("%i, ", c);
|
|
}
|
|
}
|
|
printf("\n");
|
|
|
|
drmModeFreeEncoder(tmpEncoderPtr);
|
|
}
|
|
|
|
printf("\nconnector count %i\n", resPtr->count_connectors);
|
|
for(uint32_t c = 0; c < resPtr->count_connectors; ++c)
|
|
{
|
|
drmModeConnectorPtr tmpConnPtr = drmModeGetConnector(fd, resPtr->connectors[c]);
|
|
printf("connector id %i, encoder id %i\n", tmpConnPtr->connector_id, tmpConnPtr->encoder_id);
|
|
drmModeFreeConnector(tmpConnPtr);
|
|
}
|
|
|
|
drmModeFreeResources(resPtr);
|
|
}
|